When to call Thread.currentThread().interrupt() and when not to call?
Asked Answered
B

3

11

From multiple articles around the internet it's advised not to swallow InterruptedException. It makes much more sense to do it with thread pool executors something like this when I'm going to reuse the same thread.

public static void main(String[] args) throws InterruptedException {

    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<?> future = executor.submit(() -> {
        printNumbers(); // first call
        printNumbers(); // second call
    });
    Thread.sleep(3_000);                                     
    executor.shutdownNow();  // will interrupt the task
    executor.awaitTermination(3, TimeUnit.SECONDS);
}

private static void printNumbers() {
    for (int i = 0; i < 10; i++) {
        System.out.print(i);
        try {
            Thread.sleep(1_000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // preserve interruption status
            break;
        }
    }
}

Code sample above from DZone.

But in the case of creating new thread each time like:

Object LOCK = new Object();

public void doSomeJob() {

    myThread = new Thread(new Runnable() {
        public void run() {
            try {
               synchronized(LOCK) {
               System.out.println("Inside run");
               LOCK.wait();
              }
            } catch(InterruptedException ignored){}
        }
    }
}

Do I still need to call Thread.currentThread().interrupt();? Will that make any sense?

Good references:

https://codepumpkin.com/interrupt-interrupted-isinterrupted-java-multithreading/

http://michaelscharf.blogspot.com/2006/09/dont-swallow-interruptedexception-call.html

Brake answered 20/8, 2019 at 14:4 Comment(6)
Aside: you may as well put the try/catch InterruptedException outside the loop, since interruption has the effect of breaking the loop.Simpatico
Good catch. You are right!Brake
I corrected about the loop as per DZone, breaking the loop was meant by the authors of sample as I understand. If disagree, please add comment that code was changed from original.Cinematograph
mmmm i'm seeing a wait method but i don't see any synchronized block.. you need to obtain a lock on a object in order to release it with the wait method... i mean: you should place a synchronized (lock) {...} block wrapping the wait callAvocado
Just another link where some related issues are explained: javaspecialists.eu/archive/Issue056.htmlJago
Sorry for being picky... should it not be private static final Object LOCK = new Object(); or at least only final for protecting the class against errornous outside programming? As I learned in my studying days any thread issues are the hardest to find, track and test...Peele
C
9

I will give an answer based on section 7.1.2 of great book Concurrency in Practice by Brian Goetz.

In your first example you use ExecutorService. ExecutorService manages it's own threads. You are not the owner of those Threads so you do not know what interruption means to them ( for example ThreadPool might choose to kill Threads that were interrupted and create new ones). That is why you should preserve interruption status when you submit a cancelable task to this pool. This citation applies to this case:

Tasks do not execute in threads they own.They borrow threads owned by a service such as a thread pool. Code that doesn't own the thread (for a thread pool, any code outside of the thread pool implementation) should be careful to preserve the interrupted status so that the owning code can eventually act on it, even if the "guest" code acts on the interruption as well. (If you are housesitting for someone, you don't throw out the mail that comes while they're away - you save it and let them deal with it when they get back, even if you do read their magazines.)

In the second case you manage an instance of Thread manually. So you are the owner of it. Therfore you decide what interruption means to this Thread and you do not have to preserve the Interruption Status in the second case if you do not want to apply any Thread Interruption Policy for it :

What you should not do is swallow the InterruptedException by catching it and doing nothing in the catch block, unless your code is actually implementing the interruption policy for a thread

Note also that Thread Interruption Policy is different than Task Cancellation Policy :

  1. Thread Interruption Policy - defines how Thread reacts to interruption (for example ThreadPool might kill Thread that was interrupted and create a new one). It is defined by the owner of the thread.
  2. Task Cancellation Policy - defines how task reacts to cancellation. Cancellation is usually implemented with interruption. The one who implements the task chooses if task in responsive to interruption. This is easily achieved if your task calls methods that throw InterruptedException. Or you can check the interruption flag of the Thread by calling Thread::isInterrupted (for example in a loop). The implementor of the task chooses how to handle this.

Also you should not take any assumptions of Thread Interruption Policy (if you are not the owner of the Thread). That is why preserving Interruption Status or rethrowing InterruptedException is considered a good practice.

Chabazite answered 20/8, 2019 at 14:40 Comment(4)
This is a correct answer! it would be a nice to mark it as correct answerAvocado
Good catch. Forgot to add synchronized(LOCK) while typing the question. Updated.Brake
So, when can one decide not to associate any Thread Interruption Policy for a thread?Brake
@Brake the owner of the Thread decides what to do if the task, that the Thread was executing, was interrupted. You can choose to do nothing but maybe there is something the owner would like to do - clean up some resources, kill the Thread and recreate it and so on. It is all up to owner of the Thread.Mcmillan
C
3

If your lock comes from java.util.concurrent.locks.Lock and is interruptible (using .lockInterruptibly()), it does make sense to interrupt the process so everything might be interrupted and cancelled.
Read chapter Implementation Considerations from the documentation.

But if your lock is non-interruptible (using .lock()) it will not make sense as you won't be able to interrupt the lock.

In your case, you're using wait() which is interruptable as written here, and will throw an InterruptedException.

Counterword answered 20/8, 2019 at 14:26 Comment(6)
So in the case of wait() should I still need to call Thread.currentThread().interrupt()?Brake
You can interrupt any thread, it will cause the lock to release. Determine which thread to interrupt will depend of your code implementation. If you want to interrupt the whole process, you should interrupt your main thread.Counterword
Bit shy to ask this question but, how interrupting this thread would interrupt my main thread?Brake
You can also interrupt one of your child thread as myThread.interrupt()Counterword
@Brake It swallows the interruption as discussed here :)Counterword
And interupting your child thread won't interrupt parent thread, in this case you don't need to call Thread.currentThread().interrupt() and not even to catch itCounterword
T
2

The explanations in DZone link https://dzone.com/articles/understanding-thread-interruption-in-java in your question are very detailed. Thread.currentThread().interrupt(); raises back interrupted exception status which is cleared before by blocking methods (sleep). It is done to ensure second loop interrupted too (it will catch the exception as it is on the same thread).

Before I finish, I wanted to emphasize on an important detail about what happens to a thread’s interruption status when a blocking code responds to interruption by throwing InterruptedException. I had left out the detail till now to avoid confusion.

Before a blocking code throws an InterruptedException, it marks the interruption status as false. Thus, when handling of the InterruptedException is done, you should also preserve the interruption status by callingThread.currentThread().interrupt().

Let’s see how this information applies to the example below. In the task that is submitted to the ExecutorService, the printNumbers() method is called twice. When the task is interrupted by a call toshutdownNow(), the first call to the method finishes early and then the execution reaches the second call. The interruption is called by the main thread only once. The interruption is communicated to the second execution of the printNumber() method by the call to Thread.currentThread().interrupt() during the first execution. Hence the second execution also finishes early just after printing the first number. Not preserving the interruption status would have caused the second execution of the method to run fully for 9 seconds.

Where to use Thread.currentThread().interrupt(); depends on your code, second example is not complete to understand the need for it.

Tisbe answered 20/8, 2019 at 15:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.