中断为什么能结束线程

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

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("被中断了");
	    }

	}
    }
}


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

中断为什么能结束线程_第1张图片


下面是一个改进的例子,用中断来进行线程的停止,因为,在线程阻塞状态下,中断会引起线程抛出一个 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("被中断了");
	    }

	}
    }
}



你可能感兴趣的:(中断为什么能结束线程)