16

Basically, what the question title says.

Thread t = new Thread(someRunnable);
t.start();
t.interrupt();
t.join(); //does an InterruptedException get thrown immediately here?

From my own tests, it seems to, but just wanted to be sure. I'm guessing Thread.join() checks the interrupted status of the thread before doing its "wait" routine?

Gray
  • 115,027
  • 24
  • 293
  • 354
XåpplI'-I0llwlg'I -
  • 21,649
  • 28
  • 102
  • 151

3 Answers3

26

Does calling Thread.interrupt() before a Thread.join() cause the join() to throw an InterruptedException immediately?

No it will not throw. Only if the current thread that is calling the join() method gets interrupted will join() throw InterruptedException. t.interrupt() is interrupting the thread you just started, while t.join() will only throw InterruptedException if the thread that is doing the join-ing (maybe the main thread?) is itself interrupted.

 Thread t = new Thread(someRunnable);
 t.start();
 t.interrupt();
 t.join();  // will _not_ throw unless this thread calling join gets interrupted

Also it is important to realize that interrupting a thread does not cancel it and join() is not like a Future in that it will return the exception the thread threw.

When you interrupt a thread, any calls the thread is making to sleep(), wait(), join(), and other interruptible methods will throw InterruptedException. If those methods are not called then the thread will continue running. If a thread does throw a InterruptedException in response to being interrupted and then quits, that exception will be lost unless you you used t.setDefaultUncaughtExceptionHandler(handler).

In your case, if the thread is interrupted and finishes because it returns, then the join will finish -- it will not throw an exception. Common thread code to handle an interrupt properly is as follows:

 public void run() {
    try {
       Thread.sleep(10000);
    } catch (InterruptedException e) {
       // a good pattern is to re-interrupt the thread when you catch
       Thread.currentThread().interrupt();
       // another good pattern is to make sure that if you _are_ interrupted,
       // that you stop the thread
       return;
    }
 }
Gray
  • 115,027
  • 24
  • 293
  • 354
  • Upvote; but it may be confusing to say that re-interrupting the thread is "a good pattern." If you've interrupted the flow of logic, isn't the original intent of the interrupt now fulfilled? I would expand on this just a bit... return immediately; or clean up anything that needs cleaning and return immediately. In any case "interrupt" is tricky; it's a dangerous language feature used in multiple ways by multiple parties... a re-interrupt is probably only necessary if you're executing downstream code that will recognize that status. – Robert May 12 '22 at 21:38
  • It's always a good pattern @Robert because you don't know if your caller also needs to check the interrupt status of the thread. reinterrupt may only be necessary in those cases but's always a good pattern because we tend to copy code around so bad patterns propagate. I'm not the only one who thinks this. – Gray May 13 '22 at 05:35
  • My point is simple: without knowledge of what the caller is doing; there are scenarios in which re-interrupting is the right thing to do and scenarios in which it is the wrong thing to do. In any case it's a good reminder to everyone: interrupt should not be taken for granted! -- and IMO avoided as a flow of control mechanism unless you know exactly how it will impact all upstream / downstream code. – Robert May 13 '22 at 11:30
  • It's a good pattern @Robert. Like all patterns there are exceptions. I encourage to do some more reading on the subject. I'm not proposing anything radical here. – Gray May 19 '22 at 18:36
  • I know this subject well; no lack of understanding on my part here (but thank you for the encouragement). Your post has a lot of good things in it--but the irony in your post and comments here is that you promote copy/paste of the code (which you also warn against) and say "it's a good pattern"; but you don't say why it is. I am simply recommending that you defend that statement (or link to information on "the pattern"). Understanding *why* is important. And in particular for a "pattern": *when* to follow that pattern is important. – Robert May 20 '22 at 11:43
  • Not sure I'm promoting copy&paste by showing a good pattern. As to _when_, I'd say _always_ unless you have good reason not to. This question wasn't about interrupts otherwise I would give an explanation. Here's some good links: https://dzone.com/articles/why-do-we-need-threadcurrentthreadinterrupt-in-int https://praveer09.github.io/technology/2015/12/06/understanding-thread-interruption-in-java/ https://www.baeldung.com/java-interrupted-exception If there is any question as to my experience with this subject, check out https://stackoverflow.com/tags/multithreading/topusers – Gray May 21 '22 at 00:49
20

interrupt() interrupts the thread you interrupted, not the thread doing the interrupting.

c.f.

Thread.currentThread().interrupt();
t.join(); // will throw InterruptedException 
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

interrupt() will interrupt the execution of referenced thread, if its affected by sleep() or wait() or join().

  1. As there is no sleep /join /wait called on the main, this would only update the interrupted flag.
  2. Verifies statement 1
  3. t1.join() pauses the execution of MAIN thread and allows t1 to execute before MAIN thread proceeds. But, it seems like main internally check Thread.currentThread().isIntercepted() and handles by raising the exception.
  4. Verifies statement 3
  5. Verifies statement 3 and also, as exception has raised intercepted flag is set back to false

Sample Code:

        t1.start();
        System.out.println(Thread.currentThread().getName()+" isInterrupted(): "+Thread.currentThread().isInterrupted());
        try {
            Thread.currentThread().interrupt(); // -- 1
            System.out.println(Thread.currentThread().getName()+" isInterrupted(): "+Thread.currentThread().isInterrupted()); // -- 2
            t1.join(); // -- 3
            System.out.println("This is never called as exception is raised"); // -- 4
        }catch(InterruptedException ex){
            System.out.println(Thread.currentThread().getName()+" isInterrupted(): "+Thread.currentThread().isInterrupted()); -- 5
        }
        System.out.println("Main continues");

Output:

main isInterrupted(): false
Thread-0: 0
main isInterrupted(): true
main isInterrupted(): false
Main continues
Thread-0: 1
Thread-0: 2
Thread-0: 3

Above call is from main()

I hope this would help understand better

Prateek Pande
  • 495
  • 3
  • 12