java取消线程实例

本文展现一个常见的取消线程的方法。this

错误实例

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

这里试图用一个标志来跳出while循环,理论上貌似可行,可是这里使用的是阻塞的操做,那么就出现一种场景,线程永远阻塞在put方法,根本就没来得及下个循环去判断cancelled这个条件,形成永远没法中止掉线程。线程

正确方法

经过中断来取消线程。设计

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

这里的关键是queue的put操做可以响应interrupt方法,抛出InterruptedException,倒不是由于while条件里头的isInterrupted,这里while条件换成boolean能够照样能够。code

小结

调用interrupt并不意味着当即中止目标线程正在进行的工做,而只是传递了请求中断的消息。对中断操做的正确理解是:它并不会真正地中断一个正在运行的线程,而只是发出中断请求,而后由线程在下一个合适的时刻中断本身。it

有些方法,例如wait、sleep和join等,将严格地处理这种请求,当它们收到中断请求或者在开始执行时发现某个已被设置好的中断状态时,将抛出一个异常。设计良好的方法能够彻底忽略这种请求,只要它们能使调用代码对中断请求进行某种处理。io

设计糟糕的方法可能会屏蔽中断请求,从而致使调用栈中的其余代码没法对中断请求做出响应。在使用静态的interrupted时应该当心,由于它会清除当前线程的中断状态。若是在调用interrupted时返回了true,那么除非你想屏蔽这个中断,不然必须对它进行处理—能够抛出InterruptedException,或者经过再次调用interrupt来恢复中断状态。class

相关文章
相关标签/搜索