Java超时
2019-06-22 本文已影响0人
悟剑声
超时处理问题:在串行过程中,需要实现一个方法来执行某种任务,而这个方法的执行时间不能超过指定值,如果超时,则调用者不管这个方法将来是否可能执行成功,都要中断它的执行,或者让这个方法返回。
可以提出三种解决方案,一种同步的解决方案和两种异步的解决方案。
串行超时
串行超时处理是指程序只有一个线程,调用者调用任务方法,完全由执行任务的方法本身进行超时处理。
public void runTask(long timeout){
long beginTime=System.currentTimeMillis();
while((System.currentTimeMillis()-beginTime<timeout)&&(任务返回判断)){
//执行循环体内的任务片段和算法
}
}
特点:
- 该方案无法处理因阻塞引起的超时情况
- 该方案不会引入新的线程
适用场景:
- 任务需要循环执行多个任务,每个任务执行时间稳定或内部包含超时机制。项目中一般要把这样的片段放到最外层。
利用wait/notify实现异步超时处理
利用多线程机制实现任务方法的异步执行很简单,只需要创建一个类实现Runnable接口,把任务放在重写的run方法中,run方法即为处理任务的方法。在主线程中使用Thread类创建并启动新任务线程即可。
让主线程在启动任务线程之后进行带超时参数的wait操作,如果任务线程超时,则wait不再等待,wait返回后主动中断任务线程;如果在超时时间内任务线程执行完毕,则通过notify方法通知主线程,这样主线程的wait方法也可以返回。
class TaskThread implements Runnable
@Override
public void run(){
//各种任务执行准备
while((任务没有被要求停止)&&(任务本身的各种判断条件)){
//本次循环中的子任务处理
//包括各种可能的IO阻塞和挂起等待操作
}
synchronized(monitor){ //此处的monitor引用必须主线程中的monitor对象
monitor.notify() //任务执行完毕,唤醒主线程的wait操作
}
}
}
public void caller(){
Object monitor = new Object();
TaskThread task = new TaskThread();
Thread thread = new Thread(task);
//对task对象进行各种set操作以初始化任务
try{
synchronized(monitor){
thread.start();
while(线程没有顺利完成){
monitor.wait(timeout);
}
//线程顺利结束,获取并处理结果
}
}catch(InterruptExceptione){
//等待已经被超时或者其他原因中断,终止线程thread
}finally{
//进行资源回收等收尾工作
}
}
利用Callable接口实现异步超时处理
为了去掉线程间的同步操作,以及能够让任务线程方法有返回值和抛出异常,可以使用Callable接口来替代Runnable接口,相应的主线程也需要相应变动。
Callable接口位于java.utils.concurrent包中,其抽象方法call()有返回值,可以抛出异常。
调用Callable接口需要ExecutorService接口实例,而获取call方法的返回值需要Future接口实例。
class TaskThread implements Callable{
@Override
public String call() throws AnyException{
//各种任务执行准备
while((任务没有被要求停止)&&(任务本身的各种判断条件)){
//本次循环中的子任务处理
//包括各种可能的IO阻塞和挂起等待操作
}
}
}
public void caller() throws InterruptedExceptio,TimeoutExceptio,ExecutorException{
TaskThread task=new TaskThread(); //实现Callable接口的任务线程类
ExecutorService exec=Executors.newFixedThreadPool(1);
//对task对象进行各种set操作以初始化任务
Future<String> future=exec.submit(task);
try{
return future.get(this.timeout,TimeUnit.MILLISECONDS);
}finally{
if(任务线程没有顺利结束){
//终止线程task
}
exec.shutdownNow();
}
}