我正在开发一个具有线程池的项目,它提交任务。可以说,每项任务都是一个链条。当任务执行时,它会执行它需要做的事情,然后检查结果。这些任务中的每一个都包含结果图(这只是一个枚举)和其他任务。这些在同一个线程中被调用,循环重复,直到没有更多任务,此时它返回到链中,将每个结果添加到集合并将其返回到主线程。 Q& D例子:
public abstract class MyCallable implements Callable<MyResponse> {
private Map<ResponseEnum, List<MyCallable>> callbacks;
public List<MyResponse> call() {
List<MyResponse> resp = new ArrayList<MyResponse>();
try{
//Run the process method and collect the result
MyResponse response = process();
List<MyCallable> next = callbacks.get(response.getResult());
if (next != null && !next.isEmpty()){
//Run within same thread, return results
for (MyCallable m : next){
resp.addAll(m.call();
}
return resp;
} else {
//No more responses, pass them back up the chain
resp.add(response);
return list;
}
//Anything goes wrong, we catch it here and wrap it in a response
} catch (Exception e){
resp.add(new MyExceptionResponse(e));
return resp;
}
}
//Implemented by all child classes, does the actual work
public abstract MyResponse process() throws Exception;
请记住,这也是我尚未真正测试过的原型,所以我知道这可能不完美或完全不可行。
我担心的是:一个任务被添加到线程池并开始执行。在主线程中,创建一个Future并在其上调用.get(N,TimeUnit)来检索结果。如果那个任务超时怎么办?我们得到一个TimeoutException。现在,在try / catch块中我可以取消Future,但是有没有办法让我取消Future并提取结果,至少就他们去了?在第四个任务停止之前,三个任务可能已执行并返回结果。 MyCallable中的try / catch应返回一个结果,如果有异常(即,调用.cancel(true)时出现InterruptedException),则将其推回到链中,但是我可以获得该结果吗?
当然,如果我首先谈到这个完全错误的话,那也很好。这是我第一次涉足多线程。
编辑:好的,考虑到这一点,在MyCallable类周围放置了一个包装器。包装器实现Callable并返回集合。集合沿着MyCallable对象链向下传递并添加结果,因此如果Future.get超时,我们可以检索集合并获得部分结果。
但是,这会带来潜在的竞争条件。如果正在调用的当前MyCallable正在等待外部服务,则Future.cancel(true)操作将在MyCallable中导致InterruptedException。捕获此异常并将异常包装在响应对象中并添加到集合中。问题是,如果主线程取消Future,在包装器或包装器中的集合上同步,然后获取集合,将在集合的获取和MyCallable中的try / catch块之间创建竞争条件集合的包装异常?或者主线程是否会等待捕获异常,然后执行下一行?
答案 0 :(得分:2)
当你获得TimeoutException
时,提交给Executor Service的任务正在快速前进:只有你的等待才收到异常。这可能意味着结果图仍然被填充。
您可以做的是使用并发映射并安全地提取超时发生后出现的任何结果。