gpt4 book ai didi

java - 如何从提交给执行者的已取消+中断的可调用项中获取异常?

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:43:47 26 4
gpt4 key购买 nike

考虑以下代码:

ExecutorService executor = Executors.newSingleThreadExecutor();
final CountDownLatch taskStarted = new CountDownLatch(1);
Future<String> future = executor.submit( new Callable<String>() {
@Override
public synchronized String call() throws Exception {
try {
taskStarted.countDown();
this.wait( 60000 );
return "foo";
}
catch( Exception iWantToGetThisExceptionOutside ) {
iWantToGetThisExceptionOutside.printStackTrace();
throw iWantToGetThisExceptionOutside;
}
}
});
assertTrue(taskStarted.await(60, TimeUnit.SECONDS));
try {
future.get(500, TimeUnit.MILLISECONDS);
fail("Timeout expected.");
} catch (ExecutionException | TimeoutException e) {
e.printStackTrace();
}
future.cancel(true); //mayInterruptIfRunning
//how to get iWantToGetThisExceptionOutside here?

有没有办法在取消后在主线程中获取iWantToGetThisExceptionOutside?我必须创建自己的执行程序吗?

编辑:只是为了说明没有抛出 ExecutionException,而是抛出 TimeoutException,它不包含任何原因。 iWantToGetThisExceptionOutside 是一个普通的 InterruptedException

编辑 2:一点澄清:任务相对简单。如果任务运行时间过长,我希望能够取消该任务。为此,我需要一个带有超时的 get call,它会在超时时抛出异常。我仍然欢迎在我的日志中添加一个堆栈跟踪条目,它显示任务被取消的WHERE。为此,我需要在 Callable 之外使用此异常。

最佳答案

您可以使用自定义的 FutureTask 帮助自己:

public class TracingFutureTask<T> extends FutureTask<T> {
private Throwable trace;
private boolean done;

public TracingFutureTask(Callable<T> callable) {
super(callable);
}
public TracingFutureTask(Runnable runnable, T result) {
super(runnable, result);
}

@Override
public void run() {
try { super.run(); }
finally { synchronized(this) { done=true; notifyAll(); }}
}

@Override
protected void setException(Throwable t) {
trace=t;
super.setException(t);
}
public synchronized Throwable getException() throws InterruptedException {
while(!done) wait();
return trace;
}

public synchronized Throwable getException(long timeout)
throws InterruptedException, TimeoutException {

for(long deadline = System.currentTimeMillis()+timeout, toWait=timeOut;
!done; toWait = deadline-System.currentTimeMillis()) {

if ( toWait <=0 ) throw new TimeoutException(
"Thread did not end in " + timeout + " milliseconds!" );
wait(toWait);
}
return trace;
}

public static <V> TracingFutureTask<V> submit(Executor e, Callable<V> c) {
TracingFutureTask<V> ft=new TracingFutureTask<>(c);
e.execute(ft);
return ft;
}
public static <V> TracingFutureTask<V> submit(Executor e, Runnable r, V v) {
TracingFutureTask<V> ft=new TracingFutureTask<>(r, v);
e.execute(ft);
return ft;
}
}

这会额外跟踪基类的异常,但与基类不同的是,即使作业已被取消,它也会记住它。这就是为什么 run() 方法和 getException() 之间有一个额外的同步,因为在取消的情况下作业可以进入取消状态(这意味着“完成”) 异常被记录之前,所以我们必须通过适当的同步引入我们自己的done状态。

它可以像这样使用:

ExecutorService executor = Executors.newSingleThreadExecutor();
TracingFutureTask<String> future=TracingFutureTask.submit(executor, new Callable<String>(){
@Override
public synchronized String call() throws Exception {
this.wait( 60000 );
return "foo";
}
});
try {
future.get(500, TimeUnit.MILLISECONDS);
fail("Timeout expected.");
} catch (ExecutionException | TimeoutException e) {
e.printStackTrace();
}
if(future.cancel(true)) {
System.err.println("cancelled.");
Throwable t = future.getException();
if(t!=null) t.printStackTrace(System.err.append("cancellation caused "));
}

(源自您的示例代码)

java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask.get(FutureTask.java:205)
at so.TestCancel.main(TestCancel.java:69)
cancelled.
cancellation caused java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at so.TestCancel$1.call(TestCancel.java:64)
at so.TestCancel$1.call(TestCancel.java:61)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at so.TracingFutureTask.run(TestCancel.java:33)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

关于java - 如何从提交给执行者的已取消+中断的可调用项中获取异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30106078/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com