balboa_21
balboa_21

Reputation: 384

Java Concurrency - Interruption Policies

I am reading Java Concurrency in Practice . In section Interruption Policies in chapter

Cancellation and Shutdown

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.

PrimeProducer

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());
        }
    }
}

main method##

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

  1. 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 ?

  2. 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

Answers (2)

Joni
Joni

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

Michał Krzywański
Michał Krzywański

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 Threads from java thread pools by default).

Upvotes: 3

Related Questions