Java任务超时处理机制实现
来源:互联网 发布:百度文库财富值淘宝 编辑:程序博客网 时间:2024/05/18 00:28
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(),这样方法在因阻塞引起的超时发生后将不会返回,因为这时根本无法执行到下次循环的判断条件处。
为了能够处理阻塞超时的情况,只能借助异步多线程方式来完成。
2.2利用wait/notify实现异步超时处理
利用多线程机制实现任务方法的异步执行很简单,只需要创建一个类实现Runnable接口,把任务放在重写的run方法中,run方法即为处理任务的方法。在主线程中使用Thread类创建并启动新任务线程即可。
但是,如果需要处理任务线程可能的超时情况,就需要wait/notify机制让主线程和任务线程同步了。具体思路是:让主线程在启动任务线程之后进行带超时参数的wait操作,如果任务线程超时,则wait不再等待,wait返回后主动中断任务线程;如果在超时时间内任务线程执行完毕,则通过notify方法通知主线程,这样主线程的wait方法也可以返回。
主线程代码框架如下,假设任务线程为TaskThread:
01
public
void
caller(){
02
Object monitor=
new
Object();
03
TaskThread task=
new
TaskThread();
04
Thread thread=
new
Thread(task);
05
//对task对象进行各种set操作以初始化任务
06
try
{
07
synchronized
(monitor){
08
thread.start();
09
while
(线程没有顺利完成){
10
monitor.wait(timeout);
11
}
12
//线程顺利结束,获取并处理结果
13
}
14
}
15
catch
(InterruptException e){
16
//等待已经被超时或者其他原因中断,终止线程thread
17
}
18
finally
{
19
//进行资源回收等收尾工作
20
}
21
}
任务线程TaskThread通过run方法实现任务,代码框架如下:
01
@Override
02
public
void
run(){
03
//各种任务执行准备
04
while
((任务没有被要求停止)&&(任务本身的各种判断条件)){
05
//本次循环中的子任务处理
06
//包括各种可能的IO阻塞和挂起等待操作
07
}
08
synchronized
(monitor){
//此处的monitor引用必须主线程中的monitor对象
09
monitor.notify()
//任务执行完毕,唤醒主线程的wait操作
10
}
11
}
这种方案可以处理因为IO或其他原因阻塞而引起任务执行超时的情况,当主线程因为wait超时抛出异常时,可以中断任务线程。但是需要注意的是,调用thread.stop()停止线程这种简单暴力的方法是不提倡使用的,而要用其他方法停止线程,而且停止一个处于阻塞状态的线程尤其复杂。
这种方案也存在如下缺点:
1、使用线程间同步操作,增加代码复杂度
2、Runnable接口的run方法没用返回值,不允许抛出异常,不便于任务完后了结果的返回
3、终止未完成的任务线程操作复杂
2.3利用Callable接口实现异步超时处理
为了去掉线程间的同步操作,以及能够让任务线程方法有返回值和抛出异常,可以使用Callable接口来替代Runnable接口,相应的主线程也需要相应变动。
Callable接口位于java.utils.concurrent包中,其抽象方法call()有返回值,可以抛出异常。调用Callable接口需要ExecutorService接口实例,而获取call方法的返回值需要Future接口实例。
主线程代码框架如下:
01
public
void
caller()
throws
InterruptedExceptio,TimeoutExceptio,ExecutorException{
02
TaskThread task=
new
TaskThread();
//实现Callable接口的任务线程类
03
ExecutorService exec=Executors.newFixedThreadPool(
1
);
04
//对task对象进行各种set操作以初始化任务
05
Future<String> future=exec.submit(task);
06
try
{
07
return
future.get(
this
.timeout, TimeUnit.MILLISECONDS);
08
}
09
finally
{
10
if
(任务线程没有顺利结束){
11
//终止线程task
12
}
13
exec.shutdownNow();
14
}
15
}
TaskThread由实现Runnable接口变成了实现Callable接口,call方法的代码和run方法类似,只不过不需要notify方法的调用了。代码框架如下:
1
@Override
2
public
String call()
throws
AnyException{
3
//各种任务执行准备
4
while
((任务没有被要求停止)&&(任务本身的各种判断条件)){
5
//本次循环中的子任务处理
6
//包括各种可能的IO阻塞和挂起等待操作
7
}
8
}
通过比较可以看出,这种方案的代码更为简洁方便,虽然当任务超时时,终止任务线程的方法依然复杂,但是相比于前一种更简洁,而且比第一种串行方案更具有通用性。
需要指出的是,如何停止一个线程是一个比较复杂而有一定技巧的工作(千万别说用Thread stop方法),因此并没有在本文中论述具体方法,这方面的知识可以参考资料[1,2],也可以参考我写的专门论述如何停止线程的文章http://blog.csdn.net/mikeszhang/article/details/8751355。
3参考资料
[1] Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated?http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html.
[2] How to Stop a Thread or a Task.http://forward.com.au/javaProgramming/HowToStopAThread.html.
[3] JavaTM Platform Standard Edition 6 API. http://www.ostools.net/apidocs/apidoc?api=jdk-zh.
[4] Bruce Eckel. Thinking in Java, 4th Edition. Prentice Hall, 2006.
http://my.oschina.net/u/1010788/blog/119361
- Java任务超时处理机制实现
- Java任务超时处理
- java多线程实现任务超时监听
- 超时机制处理
- Android超时机制处理
- Java定时启动任务以及Heritrix超时处理
- Java多线程任务超时结束的5种实现方法
- Java多线程任务超时结束的5种实现方法
- Android超时机制的处理
- JAVA处理线程超时
- JAVA 超时中断处理
- JAVA处理线程超时
- JAVA HttpURLConnection超时处理
- JAVA处理线程超时
- java线程超时处理
- JAVA处理线程超时
- JAVA处理线程超时
- java 超时任务---设定任务执行时长,超时停止
- 高精度加法
- 3. Longest Substring Without Repeating Characters
- 自定义View控件之特殊的饼形图(环形图)
- openframeworks加载半透明视频,文字,图片
- [机器学习]斯坦福公开课-第3课-局部加权线性回归和logistic回
- Java任务超时处理机制实现
- 【LeetCode-26】 Remove Duplicates from Sorted Array(C++)
- 显示全局的Toast 防止toast重复弹出
- HTTP Status 400服务器返回400啥意思
- openwrt 遇到问题三 高通9531编译过程
- Struts2 封装集合或Map的数据
- 组合数学笔记之四——“递推关系和生成函数”
- 斜率优化+单调队列优化DP
- JAVA处理线程超时