在FutureTask.get的CancellationException异常之后访问底层Callable的首选方法是什么?
我有以下代码 -
public class Ping implements Callable
{
public Ping(String serverName)
{
// stuff
}
// call() method, etc.
}
// other code
futures = executor.invokeAll(callables, TIMEOUT_SECONDS, TimeUnit.SECONDS);
for (Future<Object> future : futures)
{
try
{
PingStatus status = (PingStatus)future.get();
// do stuff
}
catch (CancellationException e)
{
// HELP: throw new RuntimeException("Could not ping " + callable.serverName);
}
}
如果达到超时,并且冒出了一个CancellationException,我想抛出一个新的异常,其中包含传递给Callable的serverName。这里最好的模式是什么?而且,为什么FutureTask不提供对构造函数传入的底层Callable的引用?
答案 0 :(得分:1)
由于任务和结果之间的分离,原始Callable无法从Future对象中检索。有许多方法会导致返回Future
个对象,这些对象不涉及使用或创建Callable对象。例如,采用可运行的方法submit(Runnable task)
。
Runnable和Callable不共享一个共同的父超类,这意味着如果将来的对象提供了检索它的能力,它将必须返回类型为Object
的对象。这简直太丑了。
幸运的是,如果您已阅读invokeAll()
中的返回列表的文档(强调我的):
表示任务的Futures列表,与迭代器为给定任务列表生成的顺序相同。
意味着保留Callable
的输入集合到返回的Future
列表的顺序。这样,您可以使用当前索引Future
来确定哪个Callable被取消。
E.g:
futures = executor.invokeAll(callables, TIMEOUT_SECONDS, TimeUnit.SECONDS);
int index = 0; // Index used for for-loop
for (Future<Object> future : futures){
try{
PingStatus status = (PingStatus)future.get();
// do stuff
}catch(CancellationException e){
Callable<Object> offendingCallable = callables.get(index);
// deal with object here
}
index++;
}
作为旁注,似乎您正在返回一个对象PingStatus
作为执行的结果。因此,您应该将自定义可调用声明为:
public class Ping<PingStatus> implements Callable{
以及您的适当未来对象Future<PingStatus>
,以避免从Object
到PingStatus
的恶意演员。