【问题标题】:How to catch RuntimeExceptions from Executors without blocking?如何在不阻塞的情况下从 Executors 捕获 RuntimeExceptions?
【发布时间】:2015-01-20 17:27:10
【问题描述】:

我有一个接受新任务的执行器服务:

ExecutorService executor = Executors.newFixedThreadPool(1000);
//stupid example with several parralel tasks
for (int i = 0; i < 1000; i++) {   
  try{       
    Runnable task = new Runnable() {
        public void run() {                
            throw new RuntimeException("foo");
        }
    };
    executor.submit(task);
  }

  catch (ExecutionException e) {
     System.out.println(e.getMessage());
  }
}

我的问题是我无法捕获 Runnable 抛出的任何异常,除非我这样做:

    Future<?> future = executor.submit(task);
    try {
        future.get();
    } catch (Exception e) {
        System.out.println("############### exception :" + e.getMessage());
    }

问题是future.get() 是阻塞的,所以如果我不能异步运行我的任务,我的任务将不会并行运行,而是按顺序运行。

我希望能够使用 Java 8 和 CompletableFuture,但我不能... 你有什么其他想法吗?

谢谢

【问题讨论】:

  • 为什么不先发送所有任务运行,然后收集结果?
  • 因为在我的实际项目中,它不是循环,而是用户操作,所以任务不断到达

标签: java concurrency


【解决方案1】:

Runnable 中的代码在单独的线程上执行,因此您必须在 run() 方法中处理其异常。

如果您需要收集所有异常以供以后处理,我会这样做:

ExecutorService executor = Executors.newFixedThreadPool(1000);
final List<Exception> exceptions = // a place to put exceptions
    Collections.synchronizedList(new ArrayList<Exception>());
for (int i = 0; i < 1000; i++) {
    Runnable task = new Runnable() {
        public void run() {
            try {
                throw new RuntimeException("foo");
            } catch (Exception e) {
                exceptions.add(e); // save the exception for later
            }
        }
    };
    executor.submit(task);
}
// wait for all the tasks to finish, then...
for (Exception e: exceptions) {
    // whatever you want to do
}

否则,如果您只想获取每个异常发生时的信息:

    Runnable task = new Runnable() {
        public void run() {
            try {
                throw new RuntimeException("foo");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

【讨论】:

  • 也许最后一次捕获应该重新抛出异常?
  • 目的只是为了保留行为...如果任务失败,除非您知道自己在做什么,否则您不想让它沉默...最终这将取决于这些任务的性质是否可以使异常静音,但除非有更多关于该问题的信息,否则我认为最好不要让它们静音。
  • @ValentinRuano 谢谢,但最后一次捕获只是为了保留 OP 显然正在做什么来捕获ExecutorService.submit() 抛出的异常。查看该方法的文档,它只抛出各种 RuntimeException,所以我删除了无关的 try..catch
  • 我等不及所有任务都完成了,因为在我的真实项目中,它不是一个循环,而是用户操作,所以任务不断到达,所以我只会在 Runnable 中处理我的错误,我猜猜这是唯一的方法,谢谢!
【解决方案2】:

在异步任务之后你需要做的任何事情都可以添加到任务本身。

for (int i = 0; i < 1000; i++) {   
    final Runnable task = new Runnable() {
        public void run() {                
            throw new RuntimeException("foo");
        }
    };
    executor.submit(new Runnable() {
        public void run() {
            try {
                task.run();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    });
}

或者你将它们组合成一个 Runnable。

【讨论】:

    【解决方案3】:

    这可能不是最好的解决方案,但我们可以创建一个父 Runnable 来完成实际 Runnable 的工作。父级将捕获您需要了解的所有异常。这是稍微复杂的方法:

    public static void main(String[] args){
            ExecutorService executor = Executors.newFixedThreadPool(1000);
            //stupid example with several parralel tasks
            for (int i = 0; i < 5; i++) {   
              Runnable task = new Runnable() {
                public void run() {   
                           throw new RuntimeException("foo");
    
                }
            };
            ParentRunnable t = new ParentRunnable();
            t.setRunnable(task, i);
            executor.submit(t);
            }
        }
    
        static class ParentRunnable implements Runnable {
    
            Runnable r;
            int index;
            public void setRunnable(Runnable r, int index){
             this.r = r;    
             this.index = index;
            }
            public void run() {
                try{
                    System.out.println("\n" + index + "\n");
                    r.run();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2010-12-13
      • 1970-01-01
      • 2019-09-09
      • 1970-01-01
      • 2020-01-01
      • 2017-01-08
      • 1970-01-01
      • 2011-09-01
      相关资源
      最近更新 更多