天天看点

Java 并发编程之任务取消任务取消

任务取消

取消分为如下几种:

  • 用户请求取消
  • 有时间限制的操作
  • 应用程序事件
  • 错误
  • 关闭

在我看到了几个开源项目中是这样的:

都是在public void run()方法内,用if判断Canceled状态。这个Canceled一般是布尔类型。并用Volatile声明,它可以确保可见性,但不能确保原子性。这个就允许其它线程对正在运行的线程执行取消操作。比如支付宝中,如果余额不足那么取消支付操作。这个是when 和what ,剩下的就是how to cancel。这些流程和保证放在一起就构成了支付的取消策略

中断

在阻塞方法中慎重使用取消操作。因为有可能方法被阻塞导致永远不能检查取消标志。

比如一个BlockingQueue<BIgInterger>类型

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

}
           

BlockingQueue为阻塞队列,他的put方法也是阻塞方法。当队列满了的时候,put被阻塞,此时消费者发送取消生产了。然后如果队列一直是满的。这个生产者将会一直阻塞在Put方法上不会有机会去检查是否被取消。

每个线程都有一个boolean类型的中断状态,当中断线程时,这个线程的中断状态将会被 设置为true,如Thread.sleep和Object.wait()都会检查线程何时中断。并且在发现中断时提前返回。

调用interrupt并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断的消息。通常中断是实现取消的最合理方法。

所以上面的那个 错误示例可改正如下

public void run(){
try{
BigInteger P =BigInteger.ONE;
while(!Thread.currentThread().isInterrupted())
	queue.put(P=P.nextProbablePrime());
}catch(InterruptedException consumed){}
//允许线程退出
}
           

响应中断

比如我们在创建一个File类的时候 或者 一个Socket的时候 经常会提示我们必须要加Try catch 或者throwsexception。可能一般只是为了代码格式选择一下,并不会做什么异常处理,其实异常处理是一个很重要的步骤,Throwsexception是在方法后加上throws Exception 这个的作用是将异常传递到调用它的那个 方法 ,然后最终需要有一个方法try catch处理异常,当然这没有硬性的规定,即使你一直throws到main方法也未尝不可。

只有实现 了线程中断策略的代码才可以屏蔽中断请求,在常规的任务和库代码中都不应该屏蔽中断请求

有一种方法可以使线程在退出之前恢复中断,用在一些不可以退出的必要线程中。

public Task getNextTask(BlockingQueue<Taskgt;queue>){
boolean interrupted=false;
try{
	while(true){
		try{
			return queue.take();
		}
		catch(InterruptedException e){
		 interrupted=true;
		 //重试
		}
	}
	finally{
		if(interrupted)
			Thread.currentThread().interrupted();
	}
}
}