Java未来<;T>;,TimeoutException,并获得部分结果

Java未来<;T>;,TimeoutException,并获得部分结果,java,multithreading,executorservice,future,callable,Java,Multithreading,Executorservice,Future,Callable,我正在处理一个项目,该项目有一个线程池,它向其中提交任务。可以说,每项任务都是一条链条。当任务执行时,它会执行它需要执行的操作,然后检查结果。这些任务中的每一个都包含一个结果映射(只是一个枚举)和其他任务。在同一个线程中调用这些结果,循环重复,直到不再有任务为止,此时它返回到链的上游,将每个结果添加到集合中,并将其返回到主线程。Q&D示例: 公共抽象类MyCallable实现了Callable{ 私有映射回调; 公共列表调用(){ List resp=new ArrayList(); 试一试{

我正在处理一个项目,该项目有一个线程池,它向其中提交任务。可以说,每项任务都是一条链条。当任务执行时,它会执行它需要执行的操作,然后检查结果。这些任务中的每一个都包含一个结果映射(只是一个枚举)和其他任务。在同一个线程中调用这些结果,循环重复,直到不再有任务为止,此时它返回到链的上游,将每个结果添加到集合中,并将其返回到主线程。Q&D示例:

公共抽象类MyCallable实现了Callable{
私有映射回调;
公共列表调用(){
List resp=new ArrayList();
试一试{
//运行process方法并收集结果
MyResponse=process();
List next=callbacks.get(response.getResult());
if(next!=null&&!next.isEmpty()){
//在同一线程内运行,返回结果
for(MyCallable m:next){
分别为addAll(m.call();
}
返回响应;
}否则{
//没有更多的响应,请将它们传递回链
分别添加(响应);
退货清单;
}
//如果出现任何问题,我们会在这里抓住它,并将其包装成一个响应
}捕获(例外e){
分别添加(新MyExceptionResponse(e));
返回响应;
}
}
//由所有子类实现,做实际工作
公共抽象MyResponse进程()引发异常;
请记住,这也是一个原型,我还没有真正测试出来,所以我知道这可能不是完美的,也不一定完全可行

我所关心的是:一个任务被添加到线程池并开始执行。在主线程中,一个未来被创建,一个.get(N,TimeUnit)调用它来检索结果。如果该任务超时怎么办?我们会得到一个TimeoutException。现在,在try/catch块中,我可以取消未来,但是否有任何方法可以取消未来并提取结果,至少要提取结果?在第四个任务暂停之前,可能已经执行了三个任务并返回了结果。try/MyCallable中的catch应该返回一个结果,如果出现异常(即调用.cancel(true)时InterruptedException),则应将其推回到链上,但我是否可以得到该结果

当然,如果我一开始就完全错了,那也很高兴知道。这是我第一次尝试多线程

编辑:好的,考虑到这一点,在MyCallable类周围放置了一个包装器。包装器实现Callable并返回集合。集合沿着MyCallable对象链传递,并添加结果,因此如果Future.get超时,我们可以检索集合并获得部分结果


但是,这会带来潜在的竞争条件。如果正在调用的当前MyCallable正在等待外部服务,则Future.cancel(true)操作将在MyCallable中导致InterruptedException。这将被捕获,异常将被包装在响应对象中并添加到集合中。问题是,如果主线程取消未来,则在包装上或包装中的集合上同步,然后获取集合,这会在在MyCallable中获取集合和try/catch块向集合中添加包装的异常?或者主线程会等待捕获异常,然后执行下一行吗?

在获取
TimeoutException
时,提交给Executor服务的任务正在愉快地执行way:只有您的等待收到了异常。这可能意味着结果映射仍在填充中


您可以做的是使用并发映射并安全地提取超时后出现的任何结果。

该映射仅用作获取下一个MyCallable的决策树。当当前结果出现时,它用于从映射中获取下一个MyCallable并执行它,依此类推。可能会生成结果收集可用,但这可能是必要的,因为如果不滚动我自己的Future类,我无法从已取消的Future中检索结果。只是不要使用返回值作为通信通道。将累积的结果存储在一个可以检索它们的位置,而不考虑将来的机制。我想这肯定是可行的,但不是也许把这些MyCallable对象放在一个本身实现Callable的包装器中,然后它调用MyCallable并向它们传递一个被填充的集合。。。