views:

102

answers:

5

I have a short version of the question:

  1. I start a thread like that: counter.start();, where counter is a thread.
  2. At the point when I want to stop the thread I do that: counter.interrupt()
  3. In my thread I periodically do this check: Thread.interrupted(). If it gives true I return from the thread and, as a consequence, it stops.

And here are some details, if needed:

If you need more details, they are here. From the invent dispatch thread I start a counter thread in this way:

public static void start() {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            showGUI();
            counter.start();
        }
    });
}

where the thread is defined like that:

public static Thread counter = new Thread() {
    public void run() {
        for (int i=4; i>0; i=i-1) {
            updateGUI(i,label);
            try {Thread.sleep(1000);} catch(InterruptedException e) {};
        }
            // The time for the partner selection is over.
        SwingUtilities.invokeLater(new Runnable() {
                public void run() {    
                frame.remove(partnerSelectionPanel);
                frame.add(selectionFinishedPanel);
                frame.invalidate();
                frame.validate();
            }
        });
    }
};

The thread performs countdown in the "first" window (it shows home much time left). If time limit is over, the thread close the "first" window and generate a new one. I want to modify my thread in the following way:

public static Thread counter = new Thread() {
    public void run() {
        for (int i=4; i>0; i=i-1) {
            if (!Thread.interrupted()) {
                updateGUI(i,label);
            } else {
                return;
            }
            try {Thread.sleep(1000);} catch(InterruptedException e) {};
        }
        // The time for the partner selection is over.
        if (!Thread.interrupted()) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {    
                frame.remove(partnerSelectionPanel);
                frame.add(selectionFinishedPanel);
                frame.invalidate();
                frame.validate();
            }
        });
        } else {
            return;
        } 
    }
};

ADDED:

Because of some reasons it does not work. I have a method which interrupts the thread:

public static void partnerSelected() {
    System.out.println("The button is pressed!!!!");
    counter.interrupt();
}

This method is activated when a button is pressed. When I press the button I see the corresponding output in the terminal (so this method is activated and it does something). But because of some reasons it does not interrupt the thread. Here is the code for the thread:

public static Thread counter = new Thread() {
    public void run() {
        for (int i=40; i>0; i=i-1) {
                if (Thread.interrupted()) {
                    System.out.println("Helloo!!!!!!!!!!!!!!!");
                    return;
                }
            updateGUI(i,label); 
            try {Thread.sleep(1000);} catch(InterruptedException e) {};
        }
            // The time for the partner selection is over.
            if (Thread.interrupted()) {
                System.out.println("Helloo!!!!!!!!!!!!!!!");
                return;
            }
        SwingUtilities.invokeLater(new Runnable() {
                public void run() {    
                frame.remove(partnerSelectionPanel);
                frame.add(selectionFinishedPanel);
                frame.invalidate();
                frame.validate();
            }
        });
    }
};

P.S. I do not see "Hello!!!!!!!!!!!!!" in the terminal...

A: 

Yes it is the way to go

Midhat
@Ricket: No it's not! It's still the standard way to interrupt a thread, because it works on a cooperative basis. Read Java Concurrency in Practice for more details.
Chris Jester-Young
@Chris I realized it and deleted my comment just after posting it; I was thinking of `stop()`.
Ricket
A: 

I'd like to edit and note that I've learned a lesson here today. There's no reason to implement a boolean as I explain in the following two paragraphs; the interrupt mechanism does that for me. For some reason I had assumed that "interrupt" stops the thread dead in its tracks (I don't know what I thought isInterrupted() did then!).

So, here is an example of what not to do. Keep on using your interrupt technique!

(please don't downvote me...)


I tend to avoid interrupt, but especially to stop a thread. In your case, you're trying to use interrupt() as an alternative to stop(), which has been deprecated for good reason. All you need to do is declare a boolean which represents whether the thread should stop counting, and have the thread continuously check that boolean value. Then, when the parent thread is ready for the counter to stop, it should set the boolean to true (stop), which will cause the counter thread to stop as soon as it checks the value again.

In your Counter thread's anonymous class definition, add public volatile boolean shouldStop;. At the beginning of run(), set shouldStop = false;. Then replace all Thread.interrupted() with shouldStop (in your if statements). Finally, instead of calling counter.interrupt(), just say counter.shouldStop = true;. You can additionally call counter.join() right after setting shouldStop=true if you want to ensure that counter has stopped before continuing.

Ricket
No, bad idea. Java has a built-in mechanism for signalling whether a thread should stop (interruption); don't subvert it.
Chris Jester-Young
+1. IMO it is prefferable to have your own flag saying whether the Thread should be running. I do not remember where did that knowledge come from, but I just remember this is the best way to do that:).
pajton
@pajton: The interrupted flag _is_ such a flag, except that it's also honoured by the JDK libraries (such as `Thread.sleep` or `Object.wait`), whereas a hand-rolled flag won't be observed by any of the standard libraries.
Chris Jester-Young
Thread.interrupt() is the best way to stop a thread, always ensuring that Thread.currentThread.interrupt() is called as per Chris's answer.http://cretesoft.com/archive/Issue146.html
Joel
@pajtron - a Thread should not only respond when it thinks it should cease to run but also when any external actors wish to stop it - which is what the interrupt mechanism is for.
Joel
@chris, @joel I do not like this interrupting mechanism, because of weird behaviour of this flag. If you catch an InterruptedException you have to set the flag by yourself, when you call Thread.interrupted() it is cleared as well...You need to be very careful not to make mistake with it. Can you think of a good example where a user defined flag would be worse that using interruption mechanism?
pajton
@pajton: If you are using built-in JDK mechanisms, such as `Thread.sleep`, or `Object.wait`, those functions can't see your user-defined flag (and therefore will keep waiting). If the interrupted flag is set, they will throw an `InterruptedException` straight away.
Chris Jester-Young
@chris When I use my own flag I would do something like thread.setRunning(false); thread.interrupt(). Hm, then it gets down to not having to care about interrupted flag weird behviour.
pajton
I don't see the point of posting what *not* to do here. All it can do is confuse people.It's difficult to imagine a practical case where you didn't want Thread.interrupt()'s own boolean with its extra semantics.
EJP
Take for instance Roman's link. That person may have benefited from looking at this page and going "why would you use an interrupt when you could just use a boolean?" - if he would then see my un-answer and realize that his method is in fact the same as the one I originally gave then he might be more open to this change. With the big bolded warning message, I don't think it's hurting anything.
Ricket
+5  A: 

Pretty close to the right idea. However, in your catch (InterruptedException) you should have:

Thread.currentThread().interrupt();

so that the interrupted status goes on again, and doesn't do the stuff in the second block.


Edit to make my point clearer (because the OP's edit seems to have missed my initial point :-P): you should write your code like this:

try {
    for (int = 40; i > 0; --i) {
        updateGUI(i, label);
        Thread.sleep(1000);
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();  // <-- THIS LINE IS IMPORTANT
}

Second edit to explain what interruption does. :-)

When you call thread.interrupt(), that thread's interrupted flag is set. That flag doesn't do anything on its own; it's just a variable. The reason for this is because interruption supports something called "cooperative thread management", where the thread's running code decides what to do when interrupted (rather than being forced to quit on the spot).

Some functions built into the JDK, like Thread.sleep, or Object.wait, or Lock.lockInterruptibly, will check the flag, and if it's set, then it'll throw an InterruptedException after clearing the flag.

So, if you're calling one of those functions, you don't need to manually check the interrupted flag. But if you're not, e.g., if you're doing intensive processing instead of waiting for something, then you should periodically check the flag.

There are two ways to check the flag:

  1. interrupted()
  2. isInterrupted()

The first one clears the interrupted flag; the second one doesn't. You have to decide which version is "more correct" for your application logic.

Chris Jester-Young
Chris Jester-Young, I do not understand when the InterruptedException will be thrown? Whenever I interrupt the thread? So, I do not need to us `if (Thread.interrupted())` at all?
Roman
@Roman: `InterruptedException` is thrown if the interrupted flag is set at the time `Thread.sleep` is called, or if the thread is interrupted sometime during the sleep. If you're not calling one of the "waiting" functions, no `InterruptedException` is thrown, so you must check it yourself.
Chris Jester-Young
@Roman: When an `InterruptedException` is thrown, the interrupted flag is cleared. So, you must set it again if you have later code that checks it. That's what the `Thread.currentThread().interrupt()` does.
Chris Jester-Young
Chris Jester-Young, I did it in a way you proposed. It works! But it looks to me that the exception is thrown by the `sleep`. So, if I interrupt the thread when it sleeps it will work (the thread will be interrupted). But what if I interrupt the thread when it does not sleep?
Roman
@Roman: If your thread does not sleep or wait in any way, then you must check the interrupted flag yourself. I've added some notes to my post to explain how that works.
Chris Jester-Young
Do I correctly understand? The exception will be throw by the `sleep` even if the interrupt was called when the thread did not sleep. But the thread will be interrupted when it tries to sleep.
Roman
@Roman: Close enough. :-)
Chris Jester-Young
A: 
Roman
The link doesn't say 'it's considered a better way' at all. It is an example of using a separate boolean but it doesn't even discuss Thread.isInterrupted() let alone say which is better. If it is better I would like to know why.
EJP
+1  A: 

Check out this article from the JavaSpecialists newsletter, which covers how to interrupt() threads and manage this properly.

Brian Agnew
+1 for the very interesting link :)
Chris Dennett