围绕错误进程包装超时的标准Java模式
我使用的是第三方函数(比如runThird()),它有无限循环的趋势,并且没有内置超时功能。但是,我可以杀死它(killThird())。有没有合适的方法来实现这一点(例如,一些并发构造) 以下是我的尝试:围绕错误进程包装超时的标准Java模式,java,concurrency,Java,Concurrency,我使用的是第三方函数(比如runThird()),它有无限循环的趋势,并且没有内置超时功能。但是,我可以杀死它(killThird())。有没有合适的方法来实现这一点(例如,一些并发构造) 以下是我的尝试: java.lang.Thread thread = new Thread(new Runnable(){ @Override public void run(){ try { Thread.sleep(TIMEOUT);
java.lang.Thread thread = new Thread(new Runnable(){
@Override
public void run(){
try {
Thread.sleep(TIMEOUT);
} catch (java.lang.InterruptedException e){
return;
}
killThird();
}
});
thread.start();
RunThirdResult rtr = runThird();
if (thread != null){
thread.interrupt();
}
但是我不确定我是否喜欢创建线程的开销,使用sleep和在runThird()返回时中断线程的方法。类似的东西?最有趣的部分是
StoppableWrapper#stop()
,因为优雅的取消是一件很难的事情,并且没有适用于所有情况的通用方法。一次需要清除文件系统,另一次需要关闭网络连接,等等。在示例中,您只需调用interrupt()
,因此我假设runThird()
会尊重被中断的情况,并会注意清理其背后的内容
class Sample {
final ExecutorService tasksExecutor = Executors.newCachedThreadPool();
class StoppableWrapper implements Runnable {
private final Runnable task;
private final CountDownLatch executed;
StoppableWrapper(Runnable task, CountDownLatch executed) {
this.task = task;
this.executed = executed;
}
void stop() {
// e.g. Thread.currentThread().interrupt()
}
@Override
public void run() {
task.run();
executed.countDown();
}
}
public void scheduleTimingOutTaskExecution(final long timeout) {
final CountDownLatch executed = new CountDownLatch(1);
final StoppableWrapper command = new StoppableWrapper(new RunThirdInstance(), executed);
tasksExecutor.execute(command);
tasksExecutor.execute(new Runnable() {
@Override
public void run() {
try {
if (!executed.await(timeout, TimeUnit.MILLISECONDS)) {
command.stop();
// additionally, you can make stop() return boolean after time-out as well and handle failure
}
} catch (InterruptedException e) {
// handle stopper exception here
}
}
});
}
}
让我们假设
runThird()
retuns Integer
// ... in your class ...
private ExecutorService executor = Executors.newCachedThreadPool();
//... then somewhere, where you want to call runThird()
Future<Integer> handle = executor.submit( new Callable<Integer>(){
@Override Integer call(){
return runThird(); // Assume you made it available here ...
}
}
Integer result;
try{
result = handle.get(TIMEOUT,UNIT); // TIMEOUT and UNIT declared somewhere above ...
}
catch(TimeoutException ex) {
killThird();
// HANDLE result not being set!
}
// ... use result.
/。。。在你们班上。。。
私有ExecutorService executor=Executors.newCachedThreadPool();
//... 然后在某个地方,您想调用runThird()
Future handle=executor.submit(new Callable()){
@重写整数调用(){
return runThird();//假设您在这里提供了它。。。
}
}
整数结果;
试一试{
result=handle.get(超时,单位);//在上面某处声明超时和单位。。。
}
捕获(TimeoutException例外){
killThird();
//处理未设置的结果!
}
//…使用结果。
我将为此使用ScheduledExecutorService。计划将其终止
volatile RunThirdResult rtr;
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.schedule(new Runnable(){
public void run(){
if(rtr == null) killThird();
}
}, TIMEOUT_IN_MILLIS, TimeUnit.MILLISECONDS);
RunThirdResult rtr = runThird();
您可以使用ExecutorService、Future和Callable(如果没有返回值,Runnable就足够了)。您可以向Executor提交一个Callable(运行
third()
),在返回的Future上,您将使用timeout进行阻塞。请注意,您可以使用TimeUnit.SECONDS.sleep(xx)
,它比普通的线程更容易被眼睛看到。sleep(xx)
;)您的第三方方法是否运行结果?@fge,是的,第三方确实返回结果。我来修正这个问题,复杂吗?我将提交一个newcallable(){public V call(){return runThird();}}
然后get(TIMEOUT,UNITS)
关于结果的未来,并在catch(TimeoutException)
中提交。(当然,正确地替换了“V”)。是的,很好,但是上面的代码在停止任务时提供了更大的灵活性——您有stop()
方法,您可以使用适当的关闭逻辑覆盖该方法。也许,OP在这种特殊情况下不需要它,但我在编写示例时是这样想的。+1比我的建议还要短,并且没有使用异常。不错……但是根据runThird/killThird的实现,可能会有副作用,对吗?如果我连续叫两次会怎么样?第一个呼叫的预定终止可能终止第二个呼叫。嗯,取决于具体实现,我不知道。“但它可以。”费尔多是的,你是对的。我们的两个实现都遭受相同的命运。除非OP提供更多信息,否则在我看来,没有什么其他可以假设的。