Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/366.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在FutureTask中捕获异常_Java_Concurrency_Executorservice_Futuretask - Fatal编程技术网

Java 如何在FutureTask中捕获异常

Java 如何在FutureTask中捕获异常,java,concurrency,executorservice,futuretask,Java,Concurrency,Executorservice,Futuretask,在发现Java 1.6(以及Eclipse)上运行的Executors.newCachedThreadPool()中的FutureTask吞噬了Runnable.run()方法中的异常后,我试图找到一种方法来捕获这些异常,而不向所有Runnable实现添加throw/catch API建议重写FutureTask.setException()应该有助于: 导致此未来报告ExecutionException,并将给定的throwable作为其原因,除非已设置或已取消此未来。当计算失败时,run方法

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

API建议重写
FutureTask.setException()
应该有助于:

导致此未来报告ExecutionException,并将给定的throwable作为其原因,除非已设置或已取消此未来。当计算失败时,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);
    }
}
公共类运行测试{
公共静态void main(字符串[]args){
MyFutureTask t=新建MyFutureTask(新建可运行(){
@凌驾
公开募捐{
抛出新的RuntimeException(“未检查的异常”);
}
});
ExecutorService=Executors.newCachedThreadPool();
服务提交(t);
}
}
公共类MyFutureTask扩展了FutureTask{
公共MyFutureTask(可运行的r){
super(r,null);
}
@凌驾
受保护的无效集合异常(可丢弃的t){
super.setException(t);
System.out.println(“异常:+t”);
}
}
我的主要问题是:如何捕获FutureTask中抛出的异常?为什么
setException
没有被调用


另外,我想知道为什么
FutureTask
没有使用
Thread.UncaughtExceptionHandler
机制,有什么原因吗?

我查看了
FutureTask
的源代码,但找不到调用
setException
的位置。
当run方法抛出可丢弃的
时,将调用来自
FutureTask.Sync
(FutureTask
的内部类)的
innerSetException
方法。此方法也在
setException
中调用

因此,javadoc是不正确的(或者很难理解…。

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);
        }
    }
}
公共类MyFutureTask扩展了FutureTask{
公共MyFutureTask(可运行的r){
super(r,null);
}
@凌驾
受保护的void done(){
试一试{
如果(!isCancelled())get();
}捕获(执行例外){
//发生异常,请处理它
System.out.println(“异常:+e.getCause());
}捕捉(中断异常e){
//不应该发生,我们在计算完成时被调用
抛出新断言错误(e);
}
}
}
您是否尝试过使用密码

  • 您需要实现接口
  • 要为池线程设置
    UncaughtExceptionHandler
    ,请在
    Executor.newCachedThreadPool(ThreadFactory)
    调用中提供
  • 您可以通过
    setUncaughtExceptionHandler(thread.UncaughtExceptionHandler eh)
使用提交任务,因为只有使用
execute
提交的任务引发的异常才会进入未捕获异常处理程序。对于提交了任何抛出异常的任务,异常被视为任务返回值的一部分。如果使用submit提交的任务在异常情况下终止,则在调用时将重新启动该任务,并将其包装在
ExecutionException
一个更好的解决方案中:

调用
futureTask.get()
检索计算结果时,如果基础
Runnable
/
Callable
引发异常,则会引发异常(ExecutionException)

ExecutionException.getCause()
将返回
Runnable
/
Callable
引发的异常


如果
可运行的
/
可调用的
被取消,它也会抛出不同的异常。

有三种标准方法和一种临时方法。 1.使用UncaughtExceptionHandler,将所创建线程的UncaughtExceptionHandler设置为

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(Thread t, Throwable ex) {..}}
*但其局限性在于它捕获线程抛出的异常,但在将来的任务中,它会被吞并。 2.制作带有专门为此目的提供的挂钩的自定义threadpoolexecutor后,请使用
afterExecute
。查看ThreadpoolExecutor的代码,通过提交>执行(有一个工作队列,
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**();
..}
  • 然后,第三种方法是在call方法内部使用简单的try-catch,但是在这里您无法捕获外部的异常

  • 解决方法是从TaskFactory的调用方法调用所有调用方法,TaskFactory是一个释放可调用项的工厂


  • 在进一步研究了速度非常慢的sun bugs数据库之后:很明显,它自2006年就被发现了,但仍然没有被修复(尽管它被声明为已修复)@Thirler-bug报告清楚地表明它在Java 7中得到了修复。
    setException
    得到了很好的使用。我复制并粘贴了你的代码,效果很好。在对任务调用
    get()
    方法时,您可能还希望尝试执行
    ExecutionException
    的try-catch。使用Callable/Future组合的方法是错误的。future.get()方法为您提供了封装在ExecutionException中的异常。捕捉得好!我使用的是执行器服务。提交错误。如何从ExecutionExc中提取状态代码