发现之后 FutureTask 运行在一个 Executors.newCachedThreadPool() Java 1.6(以及 Eclipse)中的吞下异常 Runnable.run() 方法,我试图想出一种方法来捕获这些,而不添加 throw/catch 到我的所有 Runnable 实施。

API 建议重写 FutureTask.setException() 应该对此有所帮助:

导致此 Future 报告 ExecutionException,并以给定的 throwable 作为其原因,除非此 Future 已被设置或已被取消。当计算失败时,run 方法会在内部调用此方法。

然而,这个方法似乎没有被调用(使用调试器运行显示异常被捕获) FutureTask, , 但 setException 不被调用)。我编写了以下程序来重现我的问题:

public class RunTest {
    public static void main(String[] args) {
        MyFutureTask t = new MyFutureTask(new Runnable() {

            @Override
            public void run() {
                throw new RuntimeException("Unchecked exception");

            }
        });

        ExecutorService service = Executors.newCachedThreadPool();
        service.submit(t);
    }
}

public class MyFutureTask extends FutureTask<Object> {

    public MyFutureTask(Runnable r) {
        super(r, null);
    }

    @Override
    protected void setException(Throwable t) {
        super.setException(t);
        System.out.println("Exception: " + t);
    }
}

我的主要问题是:如何捕获 FutureTask 中抛出的异常?为什么不 setException 接到电话吗?

我也想知道为什么 Thread.UncaughtExceptionHandler 机制未被使用 FutureTask, ,这有什么原因吗?

有帮助吗?

解决方案

setException 可能不是为了覆盖而制作的,但可以让您将结果设置为例外,如果需要。您想做的是覆盖 done() 方法并尝试获得结果:

public class MyFutureTask extends FutureTask<Object> {

    public MyFutureTask(Runnable r) {
        super(r, null);
    }

    @Override
    protected void done() {
        try {
            if (!isCancelled()) get();
        } catch (ExecutionException e) {
            // Exception occurred, deal with it
            System.out.println("Exception: " + e.getCause());
        } catch (InterruptedException e) {
            // Shouldn't happen, we're invoked when computation is finished
            throw new AssertionError(e);
        }
    }
}

其他提示

您是否尝试过使用 UncaughtExceptionHandler?

  • 您需要实施 UncaughtExceptionHandler 界面。
  • 设置一个 UncaughtExceptionHandler 对于泳池线程,提供一个 ThreadFactory 在里面 Executor.newCachedThreadPool(ThreadFactory) 称呼。
  • 您可以通过通过 setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

提交任务 ExecutorService.execute, ,因为只有从提交的任务中提出的例外 execute 求助于未被发达的例外处理程序。对于提交的任务 ExecutorService.submit 任何抛出的例外都被认为是任务返回值的一部分。如果与提交终端提交的任务有例外 Future.get, ,包裹 ExecutionException

一个更好的解决方案:Java FutureTask 完成检查

你打电话时 futureTask.get() 要检索计算结果,如果底层存在,它将抛出异常(ExecutionException) Runnable/Callable 抛出异常。

ExecutionException.getCause() 将返回异常 Runnable/Callable 扔了。

如果 Runnable/Callable 取消了。

我看了看的源代码 FutureTask 找不到哪里 setException 被称为。
有一个 innerSetException 方法 FutureTask.Sync (内部阶级 FutureTask)被称为 Throwable 被运行方法抛出。此方法也被调用 setException.
因此,它像Javadoc这样的接缝不正确(或很难理解...)。

有三种标准的方式和一种即兴的方法。 1.使用unnucaughtexceptionHandler,将创建线程的unnewtexceptionHandler设置为

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(Thread t, Throwable ex) {..}}

*但是限制是它抓住了线程所抛出的例外,但如果将来任务,它被吞噬了。 2.使用 afterExecute 在制作了带有钩子的自定义螺纹Poolexecutor之后,该挂钩专门为此目的提供了。查看threadpoolexecutor的代码,通过提交> execute(有一个工作形, workQueue.offer),将任务添加到工作队列中

   final void runWorker(Worker arg0) {
  Thread arg1 = Thread.currentThread();
  Runnable arg2 = arg0.firstTask;
  ..
     while(arg2 != null || (arg2 = this.**getTask()**) != null) {
        arg0.lock();
        ..
        try {
           this.beforeExecute(arg1, arg2);
           Object arg4 = null;
           try {
              arg2.run();
           } catch (RuntimeException arg27) {
             ..
           } finally {
              this.**afterExecute**(arg2, (Throwable)arg4);
           }

  }

getTask() {..
 this.workQueue.**poll**();
..}
  1. 然后,第三个是在呼叫方法中使用简单的尝试捕获,但是您无法在此处捕获异常。

  2. 解决方法正在从taskfactory的调用方法中调用所有调用方法,该方法是释放可销售物的工厂。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top