1、任务取消
调用interrupt并不意味着必然停止目标线程正在进行的工作;它仅仅传递了请求中断的消息。
静态的interrupt应该小心使用,因为它会清除并发线程的中断状态。
中断是实现取消最明智的选择。
class PrimeProducer extends Thread{
private final BlockingQueue queue;
PrimeProducer(BlockingQueue queue){
this.queue = queue;
}
public void run(){
try{
BigInteger p = BigInteger.ONE;
while(!Thread.currentThread().isInterrupt())
queue.put(p = p.nextProbablePrime());
}catch(InterruptedException consumed){
/*允许线程退出*/
}
}
}
因为每一个线程都有其自己的中断策略,所以你不应该中断线程,除非你知道中断这个线程意味着什么。
只有实现了线程中断策略的代码才可以接收中断请求。通过目的的任务和库的代码绝对不应该接收中断请求。
通过Future来取消任务:
public static void timeRun(Runnable r,long timeout,TimeUnit unit)throws InterruptedException{
Future task = taskExec.submit(r);
try{
task.get(timeout,unit);
}catch(TimeoutException e){
//下面任务会被取消
}catch(){
//task中抛出的异常;重抛出
throw launderThrowable(e.getCause());
}finally{
//如果任务已经结束,是无害的
task.cancle(true); //interrupt if running
}
}
线程阻塞,不可中断:java.io中的同步Socket I/O;java.nio中的同步I/O;Selector的异步I/O;获得锁。
用newTaskFor封装非标准取消。
2、停止基于线程的服务
ExecutorService提供了shutdown和shutdownNow方法,其他线程持有的服务也应该提供类似的关闭机制。
对于线程持有的服务,只要服务的存在时间大于创建线程的方法存在时间,那么就应该提供生命周期方法。
3、处理反常的线程终止
在一个长时间运行的应用程序中,所有的线程都要给未捕获异常设置一个处理器,这个处理器至少要将异常信息记入日志中。
4、关闭JVM
线程分为两种:普通线程和精灵线程。JVM启动时创建的所有线程,除了主线程以外,其它都是精灵线程(比如垃圾回收器和其它类型线程)。
应用程序中,精灵线程不能替代服务对生命周期恰当、良好的管理。
使用finally块和显式close方法的结合来管理资源,会比使用finalizer起到更好的作用。避免使用finalizer。
使用FutureTask和Executor框架可以简化构建可取消的任务和服务。