I am reading Java Concurrency in Practice . In section Interruption Policies in chapter
Its mentioned
A task should not assume anything about the interruption policy of its executing thread unless it is explicitly designed to run within a service that has a specific interruption policy. Whether a task interprets interruption as cancellation or takes some other action on interruption, it should take care to preserve the executing thread's interruption status. If its not going to propagate InterruptedException to its caller, it should restore the interruption status after catching InterruptionException: Thread.currentThread().interrupt()
So I tried to play around with listing sample to understand. But I am confused with the output.
public class CorrectPrimeProducer extends Thread {
private final BlockingQueue<BigInteger> queue;
public CorrectPrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+" interrupt status in producer:" + Thread.currentThread().isInterrupted());
BigInteger p = BigInteger.ONE;
while (!Thread.currentThread().isInterrupted()) {
queue.put(p = p.nextProbablePrime());
}
} catch (InterruptedException e) {
/* Allow thread to exit */
Thread.currentThread().interrupt();
System.out.println(Thread.currentThread().getName()+" interrupt status in producer catch:" + Thread.currentThread().isInterrupted());
}
}
}
public static void main(String[] args) throws InterruptedException {
BlockingQueue<BigInteger> primes = new LinkedBlockingQueue<>();
CorrectPrimeProducer generator = new CorrectPrimeProducer(primes);
generator.start();
try {
while (needMorePrimes()) {
consume(primes.take());
}
} finally {
generator.interrupt();
}
TimeUnit.SECONDS.sleep(5);
System.out.println(generator.getName()+" interrupt status in main:"+generator.isInterrupted());
}
//do something
private static void consume(BigInteger take) {
System.out.println(take);
}
private static int counter = 1;
private static boolean needMorePrimes() {
counter++;
if(counter == 10){
// after counter reaches 10 return false
return false;
}
return true;
}
Output:
// when TimeUnit.SECONDS.sleep(5); in main class is not commented
Thread-0 interrupt status in producer:false
2
3
5
7
11
13
17
19
Thread-0 interrupt status in producer catch:true
Thread-0 interrupt status in main:false
//When TimeUnit.SECONDS.sleep(5); in main class is commented
Thread-0 interrupt status in producer:false
2
3
5
7
11
13
17
19
Thread-0 interrupt status in main:true
Thread-0 interrupt status in producer catch:true
Question
Just by adding TimeUnit.SECONDS.sleep(5) in main thread in main class. The executing thread (ie, generator) interrupt status is getting reset. If I comment the TimeUnit.SECONDS.sleep(5) method then in that case interrupt status is retained. Why is this happening and how ?
In book it's mentioned A thread should be interrupted only by its owner . Here in the above example who is the owner ? I think its main method thread.
By adding TimeUnit.SECONDS.sleep(5)
you are giving enough time for the thread to terminate.
When a thread terminates, its interrupt flag is cleared.
This is not documented in the specification, but it's what happens. See for example this bug report:
There is no specification being violated here so I've made this an enhancement request rather than a bug. Arguably the lack of specification is a bug - we did intentionally specify that "interrupt after termination need have no affect" to deal with the fact that the interrupt state is stored in the VM and no longer exists once a thread has terminated. However we neglected to reflect that in the Thread.isInterrupted spec.
Without the extra sleep
, I suspect that in theory you could see both true
and false
interrupt status because there's a race condition, but it's far more likely you will see true
thanks to thread scheduling. The time window where the interrupt status is false, between the exception being thrown and it the interrupt status being restored in the catch block, is incredibly small.