在CancelClount之后访问可调用FutureTask.get的异常异常

时间:2015-04-28 13:59:30

标签: java

在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的引用?

1 个答案:

答案 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>,以避免从ObjectPingStatus的恶意演员。