Thomas Phan
Thomas Phan

Reputation: 247

Java thread not stopping even after calling interrupt

I'm calling interrupt on day 370, and then calling it again during the catch block during the run method of the other classes. I also have a while condition that loops while thread is not interrupted, but for some reason, it's not working, and I have no idea why. I know I can use variable flag instead, but I want to try making interrupt() works. I've look at multiple sites already, but none seems to work for me. Please help.

public class Elf implements Runnable {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            // wait a day
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

public class Main {
    public static void main(String args[]) {
        Scenario scenario = new Scenario();
        // create the participants
        // Santa
        scenario.setSanta( new Santa(scenario) );
        Thread th = new Thread(scenario.getSanta());
        th.start();
        // The elves: in this case: 10
        for (int i = 0; i != 10; i++) {
            Elf elf = new Elf(i + 1, scenario);
            scenario.getElves().add(elf);
            th = new Thread(elf);
            th.start();
        }
        // The reindeer: in this case: 9
        for (int i = 0; i != 9; i++) {
            Reindeer reindeer = new Reindeer(i + 1, scenario);
            scenario.getReindeers().add(reindeer);
            th = new Thread(reindeer);
            th.start();
        }
        // now, start the passing of time
        for (int day = 1; day < 500; day++) {
            // wait a day
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            // turn on December
            if (day > (365 - 31)) {
                scenario.setDecember(true);
            }
            // interrupt flag is set here
            if (day == 370) {
                th.interrupt();
            }
            // print out the state:
            System.out.println("***********  Day " + day
                    + " *************************");
            scenario.getSanta().report();
            for (Elf elf : scenario.getElves()) {
                elf.report();
            }
            for (Reindeer reindeer : scenario.getReindeers()) {
                reindeer.report();
            }
        }
    }
}

I've only included the Elf class here, but the other classes are of the same structure with almost the same code in it. Right now the program finishes with the red square (terminate button) still lit, and I read that that is an indication that there are still threads running. I'm not sure why it's not stopping.

Upvotes: 1

Views: 1639

Answers (1)

RealSkeptic
RealSkeptic

Reputation: 34608

A variable declared as Thread th is a reference to an object of type Thread. It's only a reference to one object. This is true, by the way, for all types, not just thread.

Whenever you put a new value into a variable, it no longer refers to the old value[1].

Thus th.interrupt() in your code will just interrupt the last thread that you assigned to it - the most recent reindeer thread.

If you want to interrupt all the threads, you'll need to keep a reference to all the threads.

A basic solution

A simple way to do this would be to use a list of Thread:

List<Thread> allThreadsToInterrupt = new ArrayList<>();

When you create a thread, you do

th = new Thread(...);
allThreadsToInterrupt.add(th);

And then at the end you can do:

for ( Thread th: allThreadsToInterrupt ) {
    th.interrupt();
}

Using a ThreadGroup

But in fact, Java has an existing class that helps you with this - the ThreadGroup class. You can do something like:

ThreadGroup elfThreads = new ThreadGroup("Elf Threads");
ThreadGroup reindeerThreads = new ThreadGroup( "Reindeer Threads" );

Now, whenever you create a thread, you should create it with a thread group:

Instead of:

th = new Thread(elf);

Use:

th = new Thread(elfThreads,elf);

Then at the end, to interrupt all the elves, you can run:

elfThreads.interrupt();

This would automatically call interrupt() on all threads that belong to the group.

Of course, you can just create one big group, but I demonstrated separating the elves and the reindeer, in case you will need them to be interrupted separately.


[1] In most cases replacing an old reference, which was the only reference to an object, with a new reference will cause the old object to be eligible for garbage collection, but threads are a little different, because if they have been started, there is a second reference to them from the current thread group (because that's the default when you don't give a thread group when you create a thread), which means that they will not be garbage-collected and they will run properly until they complete.

Upvotes: 3

Related Questions