中断为什么能结束线程

来源:互联网 发布:傻瓜电子杂志制作软件 编辑:程序博客网 时间:2024/04/30 23:16

一个常用但但并不一定能中断线程方法(因为如果此线程阻塞,则前面的判断可能会永远执行不到)

package seven;import java.math.BigInteger;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;import common.Utils;public class PrimeProducer extends Thread {    final BlockingQueue<BigInteger> queue;    private volatile boolean cancelled = false;    public PrimeProducer(BlockingQueue queue) {this.queue = queue;    }    @Override    public void run() {BigInteger p = BigInteger.ONE;/** * 分析下面循环的执行过程 当线程执行时,检测当前线程的cancelled标志,如果没有被设置true,那么执行 queue.put方法 * 此方法有可能导入线程阻塞,如果我们上面循环条件用 !cancelled进行判断的话,当消费者 * 要求阻塞生产者线程时,会判断canceled状态,而当前生产者处于阻塞状态,无法无法进行 * cancelled值的比较,而消费者可能不再消费,此时queue一直处于满的状态,会一直阻塞, 所以当前的停止线程并不适用 */while (!cancelled) {    try {queue.put(p = p.nextProbablePrime());System.out.println(Thread.currentThread().getName() + " 生产数字 "+ p);    } catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + " 线程中断");    }}    }    public void cancel() {this.cancelled = true;    }    public static void main(String args[]) {BlockingQueue<BigInteger> queue = new ArrayBlockingQueue<BigInteger>(3);PrimeProducer producer = new PrimeProducer(queue);producer.start();for (;;) {    try {System.out.println(Thread.currentThread().getName() + "消费数据 "+ queue.take()); // 从队列取出一个数Utils.sleep(1); // 停止1s,显示出消费速度慢于生产速度 producer.cancel(); // 消费者请求停止生产 break; // 消费者停止消费    } catch (InterruptedException e) {System.out.println("被中断了");    }}    }}


线程将不会停止,而是一直阻塞到这个地方



下面是一个改进的例子,用中断来进行线程的停止,因为,在线程阻塞状态下,中断会引起线程抛出一个 InterruptedException 而且设置中断标志位,这样,在线程阻塞的时候

我们也可以照样将线程停止;只是有一点要注意,在线程阻塞处理中断时,会抛出一个异常,而且设置中断标志位,线程由waitingQueue 进入到 Runnable Queue,

等待JVM的再次调度,再次调试时,就是从 catch捕获的地方开始执行了



为什么要将 while 写在了循环之中,而不是写在 try  之外?
   当线程中 put 处于阻塞状态时,我们不能利用前面的那个例子进行线程停止,我们是利用的线程中断,主线程向 这个线程发送了
   一个中断请求,而这个线程在阻塞状态收到一个中断请求会产生一个InterruptedException,然后将 中断标记置为 false(也就是清空
   中断标记),如果线程不处于阻塞状态收到了一个中断请求,那么线程的中断标志位会被置为 trur,也就是这一点,让我们把循环写在了 catch 中的,如果线程不处于阻塞
   ,收到一个抗洪请求后,中断标志为 true,这样循环的条件就不满足,线程会停止,而线程处于阻塞状态时,收到一个抗洪请求时,抗洪标记会被清除,那么
   如果循环在 catch 外的话,执行完catch 还会在执行循环,因此,只能利用catch跳出循环,而结束线程

package seven;import java.math.BigInteger;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;import common.Utils;public class PrimeProducerStop extends Thread {    final BlockingQueue<BigInteger> queue;    private volatile boolean cancelled = false;    public PrimeProducerStop(BlockingQueue queue) {this.queue = queue;    }    /**     * 解析下面的这段代码:     *    为什么要将 while 写在了循环之中,而不是写在 try  之外?   当线程中 put 处于阻塞状态时,我们不能利用前面的那个例子进行线程停止,我们是利用的线程中断,主线程向 这个线程发送了   一个中断请求,而这个线程在阻塞状态收到一个中断请求会产生一个InterruptedException,然后将 中断标记置为 false(也就是清空   中断标记),如果线程不处于阻塞状态收到了一个中断请求,那么线程的中断标志位会被置为 trur,也就是这一点,让我们把循环写在了 catch 中的,如果线程不处于阻塞   ,收到一个抗洪请求后,中断标志为 true,这样循环的条件就不满足,线程会停止,而线程处于阻塞状态时,收到一个抗洪请求时,抗洪标记会被清除,那么   如果循环在 catch 外的话,执行完catch 还会在执行循环,因此,只能利用catch跳出循环,而结束线程     */    @Override    public void run() {BigInteger p = BigInteger.ONE;try {    while (!Thread.currentThread().isInterrupted()) {//为什么要将循环写在 try{}之中,而不是之外?queue.put(p = p.nextProbablePrime());    System.out.println(Thread.currentThread().getName() + " 生产数字 " + p);    }} catch (InterruptedException e) {//让catch 直接跳出循环,这样就起到了停止线程的作用    System.out.println(Thread.currentThread().getName() + " 线程中断");    System.out.println(Thread.currentThread().isInterrupted());}System.out.println(Thread.currentThread().getName() + " is over");    }    public void cancel() {interrupt();    }    public static void main(String args[]) {BlockingQueue<BigInteger> queue = new ArrayBlockingQueue<BigInteger>(3);PrimeProducerStop producer = new PrimeProducerStop(queue);producer.start();for (;;) {    try {System.out.println(Thread.currentThread().getName() + "消费数据 "+ queue.take()); // 从队列取出一个数Utils.sleep(1); // 停止1s,显示出消费速度慢于生产速度 producer.cancel(); // 消费者请求停止生产 break; // 消费者停止消费    } catch (InterruptedException e) {System.out.println("被中断了");    }}    }}



原创粉丝点击