3

I got a question about interrupting threads in Java. Say I have a Runnable:

public MyRunnable implements Runnable {
    public void run() {
        operationOne();
        operationTwo();
        operationThree();
    }
}

I want to implement something like this:

Thread t = new Thread(new MyRunnable());
t.run();

... // something happens
    // we now want to stop Thread t

t.interrupt(); // MyRunnable receives an InterruptedException, right?

... // t is has now been terminated.

How can I implement this in Java? Specifically, how do I catch the InterruptedException in MyRunnable?

ryyst
  • 9,563
  • 18
  • 70
  • 97

5 Answers5

3

I recommend testing for Thread.isInterrupted(). Javadoc here. The idea here is that you are doing some work, most likely in a loop. On every iteration you should check if the interrupted flag is true and stop the work.

while(doingWork && !Thread.isInterrupted() {
  // do the work
}

Edit: To be clear, your thread won't receive an InterruptedException if the sub tasks are not blocking or worst, eat that exception. Checking for the flag is the right method but not everybody follows it.

Amir Raminfar
  • 33,777
  • 7
  • 93
  • 123
  • What if I need to check _during_ a given operation? – ryyst Dec 06 '11 at 18:14
  • @ryyst you will have to check during that given opertaions – John Vint Dec 06 '11 at 18:15
  • You need to check for that condition inside each condition. If each of those conditions are short lived then no harm, but if each one is doing some work then you should check in operation also. – Amir Raminfar Dec 06 '11 at 18:15
  • @JohnVint: Those operations are part of an API, so I can't change them. – ryyst Dec 06 '11 at 18:16
  • @ryyst so to understand correctly. You have a few operations that you have no control over and you want to stop them? – Amir Raminfar Dec 06 '11 at 18:17
  • @AmirRaminfar: Exactly. Note that there are asynchronous variants of the operations, so I can do `a_operationOne()` and then `waitCompleted()` to wait until the operation is done. – ryyst Dec 06 '11 at 18:19
  • 1
    I am not certain there is a way to do this. If `operationOne()` doesn't honor the interrupt flag then you have no choice to wait for each operation to complete and check your self. If it is something that is looking for disk IO or network then it should honor the interrupt flag. You can read more about this at http://stackoverflow.com/questions/671049/how-do-you-kill-a-thread-in-java – Amir Raminfar Dec 06 '11 at 18:22
  • @ryyst if API involves calls honoring `Thread.interrupt` when not all lost. If not, call API async way and have your code check interruption status instead. – Victor Sorokin Dec 06 '11 at 18:33
  • @VictorSorokin: How should my code check the interruption status when I'm using the asynchronous calls? – ryyst Dec 06 '11 at 18:39
  • From _Java Concurrency in Practice_, page 140: Thread.interrupted() "should be used with caution" because it clears the interrupted status flag. Safer to use isInterrupted(). – user949300 Dec 06 '11 at 18:57
  • @user949300 I have used `isInterrupted()` in javadoc. But made the mistake to not write the code correctly. Fixed thanks. – Amir Raminfar Dec 06 '11 at 19:01
  • @ryyst I meant to say that the only way you can deal with API, unless it is itself handles `Thread.interrupt` properly, is to check interruption status in your code periodically. All work with API in this case will be done in separate thread of yours. Once you detect interruption, you set some flag on that thread which singals that it's time to quit. So you either allow *one* API call to finish after you set that flag, or just exit application altogether. – Victor Sorokin Dec 06 '11 at 19:03
  • @VictorSorokin I think I know what you are saying. To reiterate, check for that flag asynchronously and if true then just return from the thread. But one should also understand that means the operation will still *continue* to execute. This may or may not be what you want. – Amir Raminfar Dec 06 '11 at 19:06
  • I don't understand the comments about "asynchronous". Unless operationOne() etc. spin off asynchronous tasks? Otherwise, within MyRunnable.run(), everything is synchronous, right? – user949300 Dec 06 '11 at 19:28
  • Yes, everything is synchronous if it is being executed in Runnable. But you can spin off a new thread called `child` and try check for the flag in `parent`. If the flag is set, then return immediately from `parent`, while `child` still continues to process. – Amir Raminfar Dec 06 '11 at 19:52
  • I see. That assumes that OperationOne, OperationTwo etc. as they blissfully continue on, don't change anything. Cause then you will be in an inconsistent state. – user949300 Dec 06 '11 at 21:47
1

First, the 2nd line of your 2nd block of code should be t.start(), not t.run(). t.run() simply calls your run method in-line.

And yes, MyRunnable.run() must check periodically, while it is running, for Thread.currentThread().isInterrupted(). Since many things you might want to do in a Runnable involve InterruptedExceptions, my advice is to bite the bullet and live with them. Periodically call a utility function

public static void checkForInterrupt() throws InterruptedException {
   if (Thread.currentThread().isInterrupted())
      throw new InterruptedException();
}

EDIT added

Since I see a comment that the poster has no control over the individual operations, his MyRunnable.run() code should look like

public void run() {
  operation1();
  checkForInterrupt();
  operation2();
  checkForInterrupt();
  operation3();
}
user949300
  • 15,364
  • 7
  • 35
  • 66
0

I think the answers above will pretty much fit your problem. I just want to add something on InterruptedException

Javadoc says:

InterruptedException :Thrown when a thread is waiting, sleeping, or otherwise paused for a long time and another thread interrupts it using the interrupt method in class Thread.

This means InterruptedException won't be thrown while running

operationOne();
operationTwo();
operationThree();

unless you are either sleeping, waiting for a lock or paused somewhere in these three methods.

EDIT If the provided code can not be changed as suggested by the nice and useful answers around here then I am afraid you have no way of interrupting your thread. As apposed to other languages such as C# where a thread can be aborted by calling Thread.Abort() Java does not have that possibility. See this link to know more about the exact reasons.

GETah
  • 20,922
  • 7
  • 61
  • 103
  • It is possible that the author of those methods considered multi-threading and checks for isInterrupted() and/or throws an InterruptedException. Though that should have been documented! – user949300 Dec 06 '11 at 18:49
0

an InterruptedThreadException is only thrown when the thread is being blocked (wait, sleep, etc.) . Otherwise, you'll have to check Thread.currentThread().isInterrupted().

Eagle
  • 153
  • 4
-1

First of all, should be class in there

public class MyRunnable extends Thread {
    public void run() {
        if(!isInterrupted()){
            operationOne();
            operationTwo();
            operationThree();
        }
    }
}

Would this work better?

Matt
  • 95
  • 6