9

I do not understand why the thread does not throw an InterruptedException when interrupted itself.

I'm trying with following snippet:

public class InterruptTest {

public static void main(String[] args) {
    MyThread t = new MyThread();
    t.start();
    try {
        t.join();
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }
}

private static class MyThread extends Thread {

    @Override
    public void run() {
        Thread.currentThread().interrupt();
    }
} }

In the API docs it says on the interrupt() method:

If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the Thread.join(), Thread.join(long), Thread.join(long, int), Thread.sleep(long), or Thread.sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

Lii
  • 11,553
  • 8
  • 64
  • 88
iberck
  • 2,372
  • 5
  • 31
  • 41

4 Answers4

27

I know this is an old question, but I think the answers above are actually not quite correct. (except @Skylion's, which doesn't really address the question...) :)

Thread.interrupt() does not throw any exceptions by itself. It does two things: First it simply sets an internal interrupted-flag and then it checks if the thread that it was called on is currently blocking on an activity like wait(), sleep(), or join(). If it finds one, then it wakes up that method and causes that method to throw the exception inside the thread it was called on (not from).

In the case where you call interrupt() from the thread itself, that thread obviously can't itself be currently blocking on one of those calls as it is currently executing your interrupt() call. So, only the internal interrupted-flag is set and no exception is thrown at all.

The next time you call one of the blocking methods (like sleep() in @OldCurmudgeon's example) from that thread, that method will notice the interrupted-flag and throw the InterruptedException.

If you don't ever call any of those methods, your thread will simply continue running until it terminates some other way and will never throw an InterruptedException. This is true even if you call interrupt() from a different thread.

So, to notice that your thread has been interrupted, you either need to frequently use one of the blocking methods that throws an InterruptedException and then quit when you receive one of those exceptions, or you need to frequently call Thread.interrupted() to check the internal interrupted-flag yourself and quit if it ever returns true. But you are also free to simply ignore the exception and the result from Thread.interrupted() completely and keep the thread running. So, interrupt() might be a little bit ambiguously named. It doesn't necessarily "interrupt" (as in "terminate") the Thread at all, it simply sends a signal to the thread that the thread can handle or ignore as it pleases. Much like a hardware interrupt signal on a CPU (which is probably where the name comes from).

To have the exception be thrown by the join() method in your main thread, you need to call interrupt() on that thread, rather than on MyThread, like so:

public static void main(String[] args) {
    MyThread t = new MyThread();
    t.setDaemon(true);  // Quit when main thread is done
    t.start();
    try {
        t.join();
    } catch (InterruptedException ex) {
        System.out.println("Now it works:");
        ex.printStackTrace();
    }
}

private static class MyThread extends Thread {
    
    private final Thread parentThread;
    
    public MyThread() {
        parentThread = Thread.currentThread();
    }

    @Override
    public void run() {
        parentThread.interrupt();  // Call on main thread!!!
        while (true);  // Keep thread running (see comments)
    }
}
Markus A.
  • 12,349
  • 8
  • 52
  • 116
  • 1
    This should be the accepted answer, it completely covers Java's interrupt mechanism, which ever java programmer should know about. – scravy Mar 12 '18 at 13:35
  • 2
    Good example, this should be the accepted answer! One improvement to the example code could be to add a Thread.sleep(1); after the parentThread.interrupt() call. When running the code on my machine the InterruptedException does not get thrown without the Thread.sleep(1). Probably because the thread dies immediately after the interrupt call and the main thread continues execution before the t.join() call gets interrupted. – Daniel Dec 02 '19 at 10:55
  • The answer is almost correct. Only problem is that it requires a call to sleep right after the run method because the thread might execute the interrupt method before the main thread calls the join method thus producing an ambiguous result on multiple runs. – Nilanshu96 Oct 26 '21 at 07:53
  • 1
    @Nilanshu96 The interrupted-state of a thread is remembered, so the race-condition you are seeing is not between the call to `interrupt` and the call to `join`, since join would still throw the exception based on the interrupted-flag set by `interrupt`. The race-condition is between the call to `join` and the thread completing its `run`-method entirely and terminating, since `join` first checks if the thread completed, in which case it simply returns, and only if the thread is not completed, `join` waits for the other thread (it's actually the internal `wait` call that throws the exception). – Markus A. Oct 27 '21 at 01:36
  • 1
    So, as Daniel said, you just need to delay the termination of the thread, which you can achieve with a sleep either before or after the `interrupt` call. – Markus A. Oct 27 '21 at 01:37
  • @MarkusA. Thanks for the clarification. I was incorrect and your explanation is the right one but still there's a race condition which can produce an ambiguous result. The result might confuse many beginners despite your answer having everything right. I was only suggesting the change for the sake of beginners who may come across your answer. – Nilanshu96 Oct 27 '21 at 08:56
  • @Nilanshu96 Agreed that it can be a bit confusing. The problem is that `Thread.sleep(...)` can throw an `InterruptedException` also, so if I added it to the code, I would have to wrap it in another `try...catch` block that also catches that same exception we're catching in the main thread, which might be even more confusing... :( Maybe adding a `while (true)` would be the cleanest? I'll do that... – Markus A. Oct 28 '21 at 05:38
  • @MarkusA. Yes, `while (true)` is certainly a lot better than `Thread.sleep(...)`. Anyway thanks for updating the answer. – Nilanshu96 Oct 28 '21 at 07:36
0

See @markus-a's answer for what should have been the accepted answer here. (Mine should be deleted, but I can't do that while it's accepted).


Exceptions are always thrown on their own thread. You have two different threads: your main thread and the one you created. There's no way the exception thrown in MyThread can be caught in the main one.

Costi Ciudatu
  • 37,042
  • 7
  • 56
  • 92
  • Thank you for the answer, so in this case when I need to evaluate if another thread is interrupted is with the isInterrupted() flag ? – iberck Oct 03 '13 at 23:34
  • 1
    It's worth mentioning that `MyThread` is never actually blocked either. It dies naturally after attempting to interrupt itself. – Muel Oct 03 '13 at 23:36
  • 3
    Actually, there won't even be an exception thrown in MyThread (see below). – Markus A. Mar 02 '18 at 22:26
  • This answer is incorrect, no exception is thrown in the OP's code. please fix and I'll reverse my vote. – Nathan Hughes Jan 29 '20 at 17:31
0

Why interrupt the thread at all? Just use

return;
Skylion
  • 2,696
  • 26
  • 50
-1

You're just being too quick - try this:

private static class MyThread extends Thread {

  @Override
  public void run() {
    try {
      Thread.currentThread().interrupt();
      Thread.sleep(5000);
    } catch (InterruptedException ex) {
      Logger.getLogger(Test.class.getName()).log(Level.SEVERE, "Oops", ex);
    }
  }
}

I get:

Oct 04, 2013 12:43:46 AM test.Test$MyThread run
SEVERE: Oops
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at test.Test$MyThread.run(Test.java:36)

note that you cannot propagate the exception out of the run method because run does not throw any exceptions.

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • You can always propagate any exception out of `run()` if you just wrap it in some `RuntimeException` (like `IllegalState..` or `IllegalArg..`) – Costi Ciudatu Oct 03 '13 at 23:51
  • 1
    exception can propagate outside the method run () but you can only caught it inside thread that throws it, isn't it? – iberck Oct 04 '13 at 00:43
  • 1
    @iberck there are several patterns to notify the parent thread if there was an exception in a thread. Here's a [relevant discussion](http://stackoverflow.com/questions/1369204/how-to-throw-a-checked-exception-from-a-java-thread) on this topic. – inder Oct 04 '13 at 05:21
  • 1
    The call to sleep() triggers the exception because it checks the thread's interrupted flag, not because it waits a while. wait() or join() or sleep(1) should all throw the exception immediately and a 10 hour busy loop without a call to these methods would not cause the exception to be thrown at all. See below for an explanation of what's really going on. – Markus A. Mar 02 '18 at 22:28