我使用 Future
以及 Callable<>
. 问题:如果 Exception
在异步执行期间发生,我需要访问用于生成可调用的。但是怎么做呢?
例子:
List<Callable<Response> tasks = new ArrayList<>();
taks.add(() -> sendRequest(req));
futures = executor.invokeAll(tasks);
for (future : futures) {
try {
Response rsp = future.get();
} catch (ExecutionException e) {
//problem: I need to access req.getType() value of the req Object here. But How?
}
}
比如:我想从 req.getType()
,所以我知道哪些异步请求失败了。并在错误消息中返回给用户。
3条答案
按热度按时间hs1ihplo1#
记住:那
ExecutionException
您正在捕获由Callable
实施。因此,如果您想在该异常中获得详细信息,那么您必须确保抛出并 Package 的异常包含所需的信息。
或者,您必须实际跟踪哪个未来属于哪个“输入参数”。就像创造一个
Map<Future, Request>
在将可调用对象推入执行器时填充的。nhaq1z212#
虽然这个问题已经得到了彻底的回答,但我想提出一些其他的想法,也许可以说明一些已经讨论过的想法。
关于结果顺序和阻塞
提交一组要在不同线程中运行的任务的一个有趣的方面是,我们无法再控制这些任务的完成顺序。有些任务可能会先运行,甚至那些先运行的任务可能需要比其他任务更长的时间才能完成。
现在考虑一下:
在上面的例子中,如果我们的第一个未来需要30秒来完成,而第二个未来只需要15秒;然后我们实际上封锁了30秒开始处理结果,但是第一个结果是在15秒之前完成的。
关键是,如果我们能在结果一出来就开始汇总,我们就可以改进。
使用executionservice
处理此类问题的一种方法是使用executorcompletionservice提交任务并控制结果。
例如:
这个
ExecutorCompletionService
工作方式类似于队列,一旦任务完成,无论该任务是什么,我们都可以轮询它或将它从队列中取出并获得结果。建议解决方案1:使用未来Map
假设我们有一个函数来计算整数的平方根:
现在假设我们要提交一组整数来计算它们的平方根。
例如:
因此,我们从流中获取每个整数,并创建一个
Callable<Integer>
他们中的每一个(即。() -> sqrt(n)
). 每个可调用函数都会得到上下文整数的平方根n
. 然后我们将这个可调用的消息传递给我们的完成服务,并从中获得一个未来(即。completionService.submit(callable)
). 然后我们把它还给你future
我们Map的键,还有整数n
Map中该键的值,这是我们在返回对象中看到的值(即。Map<Future<Double>, Integer> tasks
)现在我们有了一组未来(来自我们提交的任务)作为键,而用来获取这些未来的整数作为值。
现在我们可以做:
既然未来是我们Map上的关键
completionService
报告一个给定的未来已经准备好了,那么我们就可以很容易地在Map上查找这个未来,并得到它的原始值n
我们提交待处理的(即。int n = tasks.get(future)
).提出解决方案2:上下文例外
处理该问题的另一种方法是确保抛出的异常包含恢复原始请求对象所需的所有上下文细节。
例如,我们可以改变
sqrt
代码如下:如果我们不能计算平方根,我们会得到一个
InvalidIntegerException
包含处理失败的原始值的。这个例外可以把原始价值还给我们。原始异常将被 Package 在
ExecutionException
由执行人服务。所以,现在我们可以这样做:
}
我比较喜欢第一种解决方案,因为我不必对抛出的异常类型做任何假设,这使得代码更易于维护。或许其他人可以评论每种策略的利弊。
iyfjxgzm3#
根据javadoc的说法
ExecutorService
将:@返回表示任务的未来列表,其顺序与迭代器为给定任务列表生成的顺序相同,每个任务列表都已完成
所以考虑到你一开始就有一个任务列表
Future
在索引处遇到失败的对象i
在这个名单上Callable
索引处的任务i
在任务列表中: