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

时间:2015-01-20 17:27:10

标签: java concurrency

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

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

由于

3 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:1)

异步执行任务后您需要执行的任何操作都可以添加到任务本身。

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。

答案 2 :(得分:0)

这可能不是最佳解决方案,但我们可以创建一个父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();
            }
        }
    }