61 Keys to Music
61 Keys to Music

Reputation: 127

How to completely stop the execution of a Thread

I searched StackOverflow but I couldnt find the answer to my question.

I have a class Main:-

public class Main {
    public static Thread game = new Thread(new Start());
    public static void main(String[] args) {
        game.start();
        try {
            game.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

And I have the game Thread(start class):-

public class Start implements Runnable {
    private Timer timer = new Timer();
    private Thread timerThread = new Thread(timer, "timer");
    @Override
    public void run() {
        ...
        try {
            play();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
    }
    public void play() throws IOException {
        ...
        timerThread.run();
        System.out.print("Enter a letter: ");
        char input = sc.next().toUpperCase().charAt(0);
        ...
        if(isPlaying) play();
    }
}

And I have the Timer class:-

public class Timer implements Runnable {

    @Override
    public void run() {
        for (int i = 1; i <= 15; i++) {
            try {
                System.out.println(i);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Main.game.interrupt();
    }
}

Now the problem comes that when I start the game, the timer also starts. But at the end of 15 seconds, Timer thread stops. But the program didn't stop executing.

After 15 seconds, the compiler is still willing to take the input. After the input, the program ceases.

I want to immediately force stop the thread. Soon after 15 seconds, I want to stop the execution of the game thread at that very instant.

I looked over at some Multithreading tutorials on Youtube and some previously asked questions at StackOverflow but I failed to find a solution.

Upvotes: 0

Views: 72

Answers (1)

Ariel Kohan
Ariel Kohan

Reputation: 694

Are you receiving a NullPointerException?

I tested your solution and that's what I got. If that's the case, your problem is that you are trying to initialize the game field in Timer before the static property in the Main class is initialized.

For the sake of your understanding let me rephrase that: When your code runs

private Thread game = Main.game;

there is nothing in Main.game and that's because Main.game will be initialized after the initialization of the Start and Timer instances.

The simplest way to solve it is to remove the private Thread game property of your Timer and just call Main.game.interrupt();

Edit 01: Once you solve the first thing, you need to understand how the thread interruption works. When you call Main.game.interrupt();, you are only going to stop it immediately if the thread is sleeping. If that's the case, the thread will throw an InterruptedException but that's not what we want and I wouldn't recommend it. In a normal flow, the execution of the .interrupt() method will set the status of the destination thread as "Interrupted" but that is only a boolean flag that doesn't change anything (yet). What you need to do, is to check the status of that flag in your recursion method so when the value the "interruption" flag is equal to true, you will change the value of isPlaying to false. And that's how your thread will stop.

In code it would be something like this:

 

public void play() throws IOException {
        ...
        timerThread.run();
        System.out.print("Enter a letter: ");
        char input = sc.next().toUpperCase().charAt(0);
        if (Thread.interrupted()) {
            System.out.println("I should interrupt myself! ;)");
            isPlaying = false;
        }
        ...
        if(isPlaying) play();
}

Hope this helps :)

Upvotes: 2

Related Questions