如何在不阻塞的情况下从 Executors 中捕获 RuntimeExceptions?

How to catch RuntimeExceptions from Executors without blocking?

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

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 但我不能... 你还有别的想法吗?

谢谢

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();
            }
        }
    };

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

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。

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

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();
            }
        }
    }