Java并发编程——取消和关闭

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提供了shutdownshutdownNow方法,其他线程持有的服务也应该提供类似的关闭机制。

对于线程持有的服务,只要服务的存在时间大于创建线程的方法存在时间,那么就应该提供生命周期方法。

3、处理反常的线程终止

在一个长时间运行的应用程序中,所有的线程都要给未捕获异常设置一个处理器,这个处理器至少要将异常信息记入日志中。

4、关闭JVM

线程分为两种:普通线程和精灵线程。JVM启动时创建的所有线程,除了主线程以外,其它都是精灵线程(比如垃圾回收器和其它类型线程)。

应用程序中,精灵线程不能替代服务对生命周期恰当、良好的管理。  

使用finally块和显式close方法的结合来管理资源,会比使用finalizer起到更好的作用。避免使用finalizer

使用FutureTask和Executor框架可以简化构建可取消的任务和服务。 



留言