java线程池中的线程超时控制

   先MARK下一篇将JDK自带线程池的工具文,讲得挺清楚。

  http://www.oschina.net/question/565065_86540

   一些系统中的外部IO调用,比如调用第三方系统的WEBSERVICE等,尽管可以设定超时时间,但若每次调用都接近超时的上限的话,在并发较大的情况下很容易会造成系统不堪重负。此时若此调用无需实时获得调用结果,则可采用newFixedThreadPool将并发调用数限制在一定数量下,其他任务自动进入内存队列。

    而开放给第三方系统的接口,在被调用时若处理较耗时,则可采用先放入线程池并立即返回的异步处理方式提高系统吞吐量。

    同时,JAVA线程池也可以同时配合可持久化的任务队列来来防止任务的丢失。

 

     最近,项目又提出,在某些场景下,还要加入线程超时机制。

     于是百度之,发现被转载最多的整体思路就是: 每启动一个线程的时候,通过join(long timeout)方法或者其他类似方法(比如java.util.concurrent.Future.get(long timeout, TimeUnit unit) )启动一个监听线程,当监听线程通过上述方法判断任务线程超时,再调用interrupt或者cancel方法退出线程。

 

      上述解决方案仔细看了下,有如下2个问题:

       1.这种方式,每执行一个任务要启动2个线程,代价未免也太大了

     个人解决方式:

          对于每种类型的线程池,完全可以采用上文中的JDK自带线程池的实现,在提交任务的时候通过如下方法获得一个Future参数。

         <T> Future<T> java.util.concurrent.ExecutorService.submit(Callable<T> task)

           而对于每一个task,实现一个可获取任务启动时间的接口。       

           将该Future对象和提交的task对象放置于一个集合对象中,并启动一个独立线程,每隔一段时间(比如1秒)遍历该集合读写,并调用 boolean java.util.concurrent.Future.isDone()方法判断是否执行完成,若未完成,则比较task的启动时间和当前时间,若超时了,则启动关闭线程的操作。

        2.如何关闭一个线程

            这是前文百度到的解决方案中最误导人的地方。

           首先JAVA目前的中断模型是协作式的,调用interrupt()或者cancel()方法,只会在执行线程中设置一个中断标志位。是否真正要中断,则要看具体程序的逻辑。

           默认可中断的JAVA操作,主要集中于那些会让线程阻塞的操作。比如sleep(),wait()等。有个简单的判别办法,就是方法声明中是否有抛出中断异常,比如Thread.sleep(long millis) throws InterruptedException

而诸如IO操作或者同步时锁获取等阻塞,则不可被中断(当然,java nio或者JDK1.5的显式的Lock方式有提供了支持中断的方法)。

           前文百度到的范例代码,都是通过sleep()作为DEMO,这就是为什么很多人抱怨实际不起作用的原   因。

           那解决方式呢? 几乎没有。强制不由分说的关闭一个线程可能会导致各种问题,比如锁不释放等。一个比较偏门的方式就是让任务代码自己实现一个关闭资源的方法,超时时由监听线程调用。比如强制close掉socket,则正在调用中的IO操作则会立刻抛出异常。这种解决方式依赖于任务线程本身的实现,的确也不是什么高明的方式。

            在此求助下,如果各位有更好的关闭线程的方式,请不吝赐教!

 

  

   

你可能感兴趣的:(java,concurrency)