Reputation: 384
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.
Upvotes: 4
Views: 202
Reputation: 111259
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.
Upvotes: 1
Reputation: 16910
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 ?
You are not using any synchronization mechanism (apart from blocking queue) between the main thread and the CorrectPrimeProducer
so when the main thread prints the status - the CorrectPrimeProducer
may not have preserved the interrupted status yet (by performing catch
block instructions) thus you get false
as the result.
When you add sleep
to the main Thread
you just increase the possibility that the CorrectPrimeProducer
thread preserves the interruption status by invoking catch
block instructions before the main thread tries to print it's status. That is why it prints true
.
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.
In this case you are the owner (the owner is the code that creates the thread) of the CorrectPrimeProducer
thread so you decide what interruption means to it. For example you could recreate it if it was interrupted (this happens for example for Thread
s from java thread pools by default).
Upvotes: 3