1 问题描述
在应用软件的开发中,经常会遇到这样的一种需求:需要实现一个方法来执行某种任务,而这个方法的执行时间不能超过指定值,如果超时,则调用者不管这个方法将来是否可能执行成功,都要中断它的执行,或者让这个方法返回。这就是超时处理问题。
根据执行任务的方法是否异步,可以把问题从两个方面分析:如果方法顺序执行,则方法执行时整个程序的控制权在执行任务的方法中,方法调用者对于任务的超时无能为力,只能寄希望于执行任务的方法能够在任务的每轮循环中判断是否超时,以便随时自己返回;如果任务方法异步执行,即执行任务的方法是另一个线程,则可以通过主线程和任务线程的线程间协作来实现任务线程的超时中断处理。
2 解决方案
根据上面对问题的分析,可以提出三种解决方案,一种同步的解决方案和两种异步的解决方案。
2.1 串行超时处理
串行超时处理是指程序只有一个线程,调用者调用任务方法,完全由执行任务的方法本身进行超时处理。
这种方案通常要求任务需要循环执行,每个循环内的计算较复杂,执行时间较长或者不确定。执行任务的方法在规划任务算法代码的同时还要考虑超时的时候能够退出。通常的代码框架如下:
1 public void runTask(long timeout){
2 long beginTime=System.currentTimeMillis();
3 //任务执行准备
4 //如下为任务算法执行
5 while((System.currentTimeMillis()-beginTime<timeout)&&(任务自身的逻辑判断)){
6 //执行循环体内的任务片段和算法
7 }
8 }
通过这种方案实现的任务超时处理最大的优点是方案简单,因为不会引入新的线程,完全串行操作,但是这种方案也有两大缺点:
1、代码混乱,因为方法除了实现任务,还要考虑超时,违反了方法的职责单一原则
2、该方案无法处理因阻塞引起的超时情况
第二个缺点是这个方案的最大限制。如果循环体内出现诸如IO阻塞而引起的程序执行挂起,比如socket.accept(),或者inputstream.read(),这样方法在因阻塞引起的超时发生后将不会返回,因为这时根本无法执行到下次循环的判断条件处。
为了能够处理阻塞超时的情况,只能借助异步多线程方式来完成。