从Java ExecutorService捕捉线程异常

10 浏览
0 Comments

从Java ExecutorService捕捉线程异常

我正在为并行计算开发框架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 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 {
    @Override
    public Integer call() {
      int nbuf = 65536;
      double[][] buf = new double[nbuf][nbuf];
      return new Integer((int) buf[0][0]);
    }
  }
}

我正在为并行计算开发JavaSeis.org的软件开发框架。我需要一个强大的机制来报告线程异常。在开发过程中,知道异常来自哪里非常有价值,所以我希望在报告时偏向于过度报告。我还希望能够在线程中处理Junit4测试。下面的方法是否合理?还是有更好的方式?

0
0 Comments

问题的原因是使用`execute`方法无法捕获线程异常,因为`execute`方法只能执行`Runnable`任务,而不能返回`Future`对象。

解决方法是使用`submit`方法代替`execute`方法,并使用`Callable`任务而不是`Runnable`任务。这样可以返回`Future`对象,从而能够捕获线程异常。

以下是代码示例:

import java.util.concurrent.*;
public class Main {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        Future future = executor.submit(new Callable() {
            @Override
            public String call() throws Exception {
                // 执行任务,可能会抛出异常
                throw new Exception("Something went wrong");
            }
        });
        try {
            String result = future.get();
            System.out.println("Result: " + result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            // 捕获线程异常
            Throwable cause = e.getCause();
            System.out.println("Exception: " + cause.getMessage());
        }
        executor.shutdown();
    }
}

以上代码中,我们使用`submit`方法提交一个`Callable`任务,并在任务中抛出了一个异常。在`try-catch`块中,我们通过`future.get()`方法获取任务的结果,如果任务抛出了异常,我们通过`ExecutionException`捕获并打印异常信息。

通过使用`submit`方法和`Callable`任务,我们成功地捕获并处理了线程异常。这种方式可以帮助我们更好地管理线程池中的异常情况。

0
0 Comments

使用Java ExecutorService时,如果使用submit()方法提交任务,无法直接获取线程抛出的异常。然而,如果需要支持submit()方法,可以通过对Callable和Runnable进行包装来解决这个问题。

解决方法是在创建ExecutorService时,继承ThreadPoolExecutor类,并重写submit()方法。在重写的submit()方法中,对传入的任务进行包装,捕获异常并进行处理。具体代码如下:

ExecutorService executor = new ThreadPoolExecutor(1, 10, 60, TimeUnit.SECONDS, new LinkedBlockingDeque()) {
    public  Future submit(final Callable task) {
        Callable wrappedTask = new Callable() {
            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);
    }
};

需要注意的是,这种方法只适用于自己创建ExecutorService的情况下,同时需要重写所有三个submit()方法。

通过以上方法,可以在使用ExecutorService的过程中捕获并处理线程抛出的异常。

0
0 Comments

问题出现的原因是使用`submit()`方法时,`ExecutorService`不会捕获线程抛出的异常。解决方法是改用`execute()`方法,并在`ThreadFactory`中安装`Thread.UncaughtExceptionHandler`来处理线程异常。如果需要使用`Future`结果,可以将其包装在`execute()`中。需要注意的是,如果`ExecutorService`是`ScheduledExecutorService`,即使调用了`execute()`方法,也不会调用`UncaughtExceptionHandler`。

以下是整理后的文章:

在使用Java的`ExecutorService`时,我们可能会遇到线程抛出异常而无法捕获的情况。这是因为当我们使用`submit()`方法时,`ExecutorService`不会捕获线程抛出的异常。那么我们该如何解决这个问题呢?

一个解决方法是改用`execute()`方法来代替`submit()`方法。使用`execute()`方法时,当线程执行失败时,会调用`Thread.UncaughtExceptionHandler`来处理异常。所以,我们可以通过将工作任务使用`execute()`方法提交给`ExecutorService`来解决这个问题。

另一个解决方法是通过创建一个`ThreadFactory`,并在所有创建的线程上安装一个`Thread.UncaughtExceptionHandler`来处理异常。然后,我们可以使用`execute()`方法来提交工作任务给`ExecutorService`,而不是使用`submit()`方法。

需要注意的是,如果我们的`ExecutorService`实际上是一个`ScheduledExecutorService`,那么即使我们调用了`execute()`方法,`UncaughtExceptionHandler`也不会被调用。所以,在这种情况下,我们需要采取其他的处理方式。

如果你对这个问题感兴趣,可以参考相关的Stack Overflow问题,其中提供了更多关于这个的问题和解决方案。

0