-1

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...

Roman
  • 124,451
  • 167
  • 349
  • 456

5 Answers5

5

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.

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • 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 Mar 21 '10 at 19:01
  • 1
    @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. – C. K. Young Mar 21 '10 at 19:04
  • 1
    @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. – C. K. Young Mar 21 '10 at 19:06
  • 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 Mar 21 '10 at 19:07
  • @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. – C. K. Young Mar 21 '10 at 19:12
  • 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 Mar 21 '10 at 19:12
0

Yes it is the way to go

Midhat
  • 17,454
  • 22
  • 87
  • 114
  • @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. – C. K. Young Mar 21 '10 at 18:28
  • @Chris I realized it and deleted my comment just after posting it; I was thinking of `stop()`. – Ricket Mar 21 '10 at 18:32
0

Edit/Preamble

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!

Original answer

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.

halfer
  • 19,824
  • 17
  • 99
  • 186
Ricket
  • 33,368
  • 30
  • 112
  • 143
  • 1
    No, bad idea. Java has a built-in mechanism for signalling whether a thread should stop (interruption); don't subvert it. – C. K. Young Mar 21 '10 at 18:28
  • +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 Mar 21 '10 at 18:30
  • @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. – C. K. Young Mar 21 '10 at 18:32
  • 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 Mar 21 '10 at 18:33
  • @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 Mar 21 '10 at 18:34
  • @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 Mar 21 '10 at 18:38
  • @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. – C. K. Young Mar 21 '10 at 18:40
  • @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 Mar 21 '10 at 18:54
  • 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. – user207421 Mar 21 '10 at 23:49
  • 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 Mar 22 '10 at 18:19
0
  1. It's considered a better way (link) to use separate volatile variable (boolean isStopped) for this purpose.

  2. Assume that interrupted() method changes value from true to false if your thread was interrupted, i.e.:

System.out.println (Thread.interrupted()); //true

System.out.println (Thread.interrupted()); //false

The alternative is isInterrupted() method.

Roman
  • 64,384
  • 92
  • 238
  • 332
  • 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. – user207421 Mar 22 '10 at 08:08
0

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

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440