【问题标题】:Rethrow checked exception from Runnable从 Runnable 重新抛出已检查的异常
【发布时间】:2013-06-06 17:23:08
【问题描述】:

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

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 块包围调用。
因此,我的主类无法知道引发了异常。

我该如何解决这个问题?

【问题讨论】:

  • 你的任务有返回值吗?
  • 不,不返回任何内容。

标签: java multithreading exception runnable


【解决方案1】:

您可以使用 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());
}

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 你不能从runnable重新抛出异常。
    • @yuris:是的,你可以:将它们包装在一些 RuntimeException 中。
    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

      如果你可以修改你的任务来实现Callable,你可以从call()中抛出一个检查异常 由于您的任务不返回值,请使用Callable&lt;Void&gt;

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

      Callable&lt;?&gt;Runnable 的不同之处在于它可以抛出已检查的异常并返回结果

      call() 的方法签名允许你抛出一个检查异常

      V call() throws Exception
      

      【讨论】:

        【解决方案5】:

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

        你需要做什么:

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

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

        【讨论】:

          猜你喜欢
          • 2011-06-01
          • 1970-01-01
          • 2017-02-14
          • 1970-01-01
          • 1970-01-01
          • 2015-04-26
          • 1970-01-01
          • 1970-01-01
          • 2011-04-15
          相关资源
          最近更新 更多