java并发编程(六)取消与关闭

接《java并发编程(五)任务执行


前面几章我们一直是创建和开启线程,而有时候我们要结束任务或线程,这并不是很容易的,因为,java 并没有提供任何机制来安全终止线程(在未来的jdk版本中会不会加入呢?)它提供了中断。这是一种机制,能够在一个线程终止另一个线程的工作。

任务取消

一种协作方式是设置某个“已请求取消”标识,而任务将定时查看该标志。下面程序,将持续枚举素数,直到它将被取消。cancle方法设置canceled标志,并且主循环在搜索下一个素数下一个之前,首先检查这个标志(canceled必须为volatile 原因请看 java内存模型
public class PrimeGenerator implements Runnable {

	private List<BigInteger> primes = new ArrayList<BigInteger>();
	private volatile boolean canceled;

	@Override
	public void run() {
		BigInteger bigInteger = BigInteger.ONE;
		while (!canceled) {
			bigInteger = bigInteger.nextProbablePrime();
			synchronized (this) {
				primes.add(bigInteger);
			}
		}
	}

	public void cancel() { this.canceled = true; }

	public synchronized List<BigInteger> get() {
		return new ArrayList<BigInteger>(primes);
	}
}
现在我们要让一个素数生成器运行1秒后停止,(虽然不是很精确,因为每一条代码是有延时的),我们可以用try finally 来完成,以保证线程会停止,否则线程会一直消耗CPU时钟周期,导致JVM退出。
	List<BigInteger> aSecondOfPrimes() throws InterruptedException {
	
		PrimeGenerator generator = new PrimeGenerator();
		new Thread(generator).start();
		try {
			Thread.sleep(1000);
		} finally {
			generator.cancel();
		}
		return generator.get();
	}

 中断

PrimeGenerator中的取消机制最终会使得搜索的素数任务退出,但是退出过程中需要花费一定的时间,然而,如果任务调度了一些阻塞方法,(BlockingQueue.put)那么可能产生一个问题——任务可能永远不会检查取消标示,永远不会结束。
为取保线程能退出,我们通常使用中断,当我们调用interrupt,并不意味着立即停止目标线程正在运行的线程,而只是传递了一个请求中断的信息,它会在线程下一个合适的的时刻中断自己。wait、sleep、join、将严格处理这种请求,当他们收到一个中断请求,或饿着开始执行时发现中断状态时,将抛出异常。
使用静态的interrupted时应该小心,因为它会清除当前线程的中断状态,如果返回true,除非你你想屏蔽这个中断,否则必须对它进行处理,抛出异常或者再次调用interrupt来恢复中断状态
try {
			...
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		}
通常,我们用中断来取消任务比检查标记更好,是最合适的取消任务方式,我们看一个更加健壮的获得素数的类。
public class PrimeProducer extends Thread{
	
	private final BlockingQueue<BigInteger> queue;
	
	public PrimeProducer(BlockingQueue<BigInteger> queue) {
		this.queue = queue;
	}

	@Override
	public void run() {
		try {
			BigInteger p = BigInteger.ONE;
			while(!Thread.currentThread().isInterrupted()) //①用线程的状态来检查
				queue.put(p = p.nextProbablePrime());
			
		} catch (InterruptedException e) {
			//中断将线程退出
		}
	}
	public void cancel() { interrupt(); }

}

我们分析下,在while时,我们有两次的检查中断,while中有一次,在执行put的时候有一次,这样我们比用flag标识有更高的效用性,通常,我们也是通过这种方式来取消线程的。

通过Future来实现中断

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值