Java cancel thread instance

  java

Order

This article shows a common method to cancel threads.

Error instance

class BrokenPrimeProducer extends Thread {
    private final BlockingQueue<BigInteger> queue;
    private volatile boolean cancelled = false;

    BrokenPrimeProducer(BlockingQueue<BigInteger> queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            BigInteger p = BigInteger.ONE;
            while (!cancelled){
                queue.put(p = p.nextProbablePrime());
            }    
        } catch (InterruptedException consumed) {
        }
    }

    public void cancel() {
        cancelled = true;
    }
}

Here, an attempt is made to jump out of the while loop with a flag, which seems feasible in theory, but the blocking operation is used here, so there is a scenario where the thread is always blocked in the put method, and there is no time to judge the cancelled condition in the next loop, resulting in the thread can never be stopped.

Correct method

To cancel a thread by interrupting.

public class PrimeProducer extends Thread {
    private final BlockingQueue<BigInteger> queue;

    PrimeProducer(BlockingQueue<BigInteger> queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            BigInteger p = BigInteger.ONE;
            while (!Thread.currentThread().isInterrupted()){
                queue.put(p = p.nextProbablePrime());
            }    
        } catch (InterruptedException consumed) {
            /* Allow thread to exit */
        }
    }

    public void cancel() {
        interrupt();
    }
}

The key here is that queue’s put operation can respond to the interrupt method and throw an InterruptedException, not because of isInterrupted in the while condition, which can be changed to boolean.

Summary

Calling interrupt does not mean stopping the work being done by the target thread immediately, but merely passing a message requesting an interrupt. The correct understanding of interrupt operation is that it does not really interrupt a running thread, but only issues an interrupt request, and then the thread interrupts itself at the next appropriate moment.

Some methods, such as wait, sleep and join, will strictly handle such requests and throw an exception when they receive an interrupt request or find a set interrupt state at the beginning of execution. Well-designed methods can completely ignore such requests as long as they enable the calling code to do some processing on interrupt requests.

Poorly designed methods may mask interrupt requests, causing other code in the call stack to fail to respond to interrupt requests. Care should be taken when using static interrupted because it clears the interrupt status of the current thread. If true is returned when calling interrupted, it must be processed unless you want to mask the interrupt-you can throw an InterruptedException or restore the interrupt state by calling Interrupt again.