2

我从我的主类执行多个任务:

ExecutorService executor = Executors.newFixedThreadPool(N);
    for (int i = 0; i < M; i++) {
    executor.execute(task);
}

executor .shutdown(); 
while (!executor.isTerminated()){} //block                          

task 是一个类implements Runnable

run()方法中,我调用了一些带有检查异常的 api,这意味着我需要用 try-catch 块包围调用。
因此,我的主类无法知道引发了异常。

我该如何解决这个问题?

4

5 回答 5

3

您可以使用 Callable 代替:

Callable<?> task = new Callable<Void> () {
    public Void call() throws Exception {
        someCodeThatThrowsCheckedExceptions();
        return null;
    }
}

然后:

Future<?> f = executor.submit(task);
try {
    f.get();
} catch (ExecutionException e) {
    System.out.println("task threw exception: " + e.getCause().getMessage());
}
于 2013-06-06T09:04:56.930 回答
0

总是重新抛出异常,让调用者知道它,否则异常可能会逃逸。你可以在 Java Concurrency in Practice 一书中找到很好的解释。对不起,我应该把它作为你的评论,但我的分数不允许我:)

于 2013-06-06T08:53:07.803 回答
0

您可以从主要异常中创建UncheckedException 。假设您已经创建了自己的UncheckedException扩展类RuntimeException,定义了所有必需的构造函数。你可以说,

    @Override
    public void run() {
        try {
            //some code that throws checked exception
        }
        catch(Exception e) {
            throw new UncheckedException(e);
        }
    }

此代码将编译,因为这里不需要throws声明

于 2013-06-06T08:56:55.517 回答
0

如果你可以修改你的任务来实现Callable,你可以从 call() 抛出一个检查异常因为你的任务不返回值,使用Callable<Void>

class Task implements Callable<Void> {
    public Void call throws YourAPIException {
        //code that throws a checked exception
        return null;
    }
}

Callable<?>不同之处Runnable在于它可以抛出一个已检查的异常并返回一个结果

的方法签名call()允许您抛出已检查的异常

V call() throws Exception
于 2013-06-06T09:07:59.330 回答
0

在我看来,好看的解决方案是实施Callable<V>而不是Runnable. 两个主要区别是Callable可以抛出已检查的异常并且它可以返回一个值。您可以通过实现来克服返回Callable<Void>

你需要做什么:

  1. 让您的任务实施Callable<Void>而不是Runnable- 更改void run()Void call() throws Exception. 无需尝试/捕获已检查的异常。添加return null;声明。
  2. 利用Future<Void> checkableResult = ExecutorService.submit(Callable<Void>)
  3. 你可以通过调用来检查它是否抛出了异常,如果它抛出了checkableResult.get(),它会抛出一个异常ExecutionException。可以通过 检索原始异常getCause()。特别注意这get()是阻塞 - 所以定期检查Callable.isDone()可能是你想要的(否则你不妨在同一个线程中运行它)。

另一种选择是将功能构建到您的Runnable(volatile boolean isDone和 a volatile Exception exception) 中 - 但为什么要重新发明轮子?

于 2013-06-06T09:23:08.307 回答