Site Search:

NoncancelableTask.java

Back>

In the following example, method getNextTask calls interruptible blocking method queue.take(). Normally, upon catching InterruptedException, the code should immedieatly call interrupt() to restore the interrupted status (so that codes outside this method or calling threads can take action) before exiting. However this method don't want to support cancellation. Instead of exiting loop upon catching InterruptedException, it chooses to fall through the interruption and try again -- just get into interruptible blocking again until queue.take() returns. Before it returns,  getNextTask restores the interrupted status in finally block (so that codes outside this method or calling threads can take action).

The main thread scheduled 3 threads to interrupt itself one second later, 2 seconds later, 3 seconds later before it calls the blocking method queue.take(). Main thread also scheduled a thread to put an element into the queue 5 seconds later, so that the main thread can get out of getNextTask and run to finish.

Notice the System.out.println established artificial happens-before relationship between threads, however, it won't dilute the point we are trying to demonstrate here.

CHAP7>cat NoncancelableTask.java 
import java.util.concurrent.*;

/**
 * NoncancelableTask
 * <p/>
 * Noncancelable task that restores interruption before exit
 */
public class NoncancelableTask {
    public Task getNextTask(BlockingQueue<Task> queue) {
        boolean interrupted = false;
        try {
            while (true) {
                try {
                    System.out.println(Thread.currentThread() + " about to block wait for element in queue, queue size: " + queue.size());
                    return queue.take();
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread() + " is interrupted, about to swallow the InterruptedException");
                    System.out.println(Thread.currentThread() + ": " + Thread.currentThread().isInterrupted());
                    interrupted = true;
                    // fall through and retry
                }
            }
        } finally {
            if (interrupted) {
                System.out.println(Thread.currentThread() + " about to restore interrupt");
                Thread.currentThread().interrupt();
            }
        }
    }

    interface Task {
    }
    
    private static ScheduledExecutorService exec = Executors.newScheduledThreadPool(2);
    
    public static void main(String[] args) throws InterruptedException {
        NoncancelableTask nct = new NoncancelableTask();
        BlockingQueue<Task> queue = new LinkedBlockingQueue<>();
        Thread t = Thread.currentThread();
        System.out.println(t + ":" + t.isInterrupted());
        exec.schedule(() -> t.interrupt(), 1, TimeUnit.SECONDS);
        exec.schedule(() -> t.interrupt(), 2, TimeUnit.SECONDS);
        exec.schedule(() -> t.interrupt(), 3, TimeUnit.SECONDS);
        exec.schedule(() -> queue.add(new Task(){}), 4, TimeUnit.SECONDS);
        nct.getNextTask(queue); 
        System.out.println(t + ":" + t.isInterrupted());
        new Thread(() -> System.out.println(Thread.currentThread() + " can act on t's interrupted status: " + t.isInterrupted())).start();
        exec.shutdown();
        exec.awaitTermination(10, TimeUnit.SECONDS);
    }
}
CHAP7>javac NoncancelableTask.java 
CHAP7>java NoncancelableTask
Thread[main,5,main]:false
Thread[main,5,main] about to block wait for element in queue, queue size: 0
Thread[main,5,main] is interrupted, about to swallow the InterruptedException
Thread[main,5,main]: false
Thread[main,5,main] about to block wait for element in queue, queue size: 0
Thread[main,5,main] is interrupted, about to swallow the InterruptedException
Thread[main,5,main]: false
Thread[main,5,main] about to block wait for element in queue, queue size: 0
Thread[main,5,main] is interrupted, about to swallow the InterruptedException
Thread[main,5,main]: false
Thread[main,5,main] about to block wait for element in queue, queue size: 0
Thread[main,5,main] about to restore interrupt
Thread[main,5,main]:true
Thread[Thread-0,5,main] can act on t's interrupted status: true

CHAP7>