从 Java ExecutorService 捕获线程异常

2022-09-02 23:43:08

我正在研究一个用于并行计算 JavaSeis.org 的软件开发框架。我需要一个强大的机制来报告线程异常。在开发过程中,了解异常来自何处具有很高的价值,因此我想在过度报告方面犯错误。我也希望能够在线程中处理 Junit4 测试。下面的方法是否合理或有更好的方法?

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class TestThreadFailure {

  public static void main(String[] args) {
    int size = 1;
    ExecutorService exec = Executors.newFixedThreadPool(size);
    ThreadFailTask worker = new ThreadFailTask();
    Future<Integer> result = exec.submit(worker);
    try {
      Integer value = result.get();
      System.out.println("Result: " + value);
    } catch (Throwable t) {
      System.out.println("Caught failure: " + t.toString());
      exec.shutdownNow();
      System.out.println("Stack Trace:");
      t.printStackTrace();
      return;
    }
    throw new RuntimeException("Did not catch failure !!");
  }

  public static class ThreadFailTask implements Callable<Integer> {
    @Override
    public Integer call() {
      int nbuf = 65536;
      double[][] buf = new double[nbuf][nbuf];
      return new Integer((int) buf[0][0]);
    }
  }
}

答案 1

考虑在执行器服务上调用 execute() 而不是 submit()。调用的线程将在失败时调用 Thread.UncaughtExceptionHandlerexecute()

只需创建一个 ThreadFactory,该站点在所有上安装 ,然后在 上调用您的工作,而不是 .Thread.UncaughtExceptionHandlerThreadsexecute()ExecutorServicesubmit()

看看这个相关的堆栈溢出问题


答案 2

我不相信在使用时有标准的“钩子”来获得这些例外。但是,如果您需要支持(这听起来很合理,因为您使用了 a ),则始终可以包装 Callables 和 Runnables:submit()submit()Callable

ExecutorService executor = new ThreadPoolExecutor(1, 10, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>()) {
    @Override
    public <T> Future<T> submit(final Callable<T> task) {
        Callable<T> wrappedTask = new Callable<T>() {
            @Override
            public T call() throws Exception {
                try {
                    return task.call();
                }
                catch (Exception e) {
                    System.out.println("Oh boy, something broke!");
                    e.printStackTrace();
                    throw e;
                }
            }
        };

        return super.submit(wrappedTask);
    }
};

当然,此方法仅在您首先是构建它时才有效。此外,请记住覆盖所有三个变体。ExecutorServicesubmit()