处理来自Java ExecutorService任务的异常

处理来自Java ExecutorService任务的异常,java,multithreading,exception,executorservice,threadpoolexecutor,Java,Multithreading,Exception,Executorservice,Threadpoolexecutor,我试图使用Java的ThreadPoolExecutor类来运行大量具有固定线程数的重载任务。每个任务都有许多地方,在此期间可能会由于异常而失败 我对ThreadPoolExecutor进行了子类化,并重写了afterExecute方法,该方法应该提供在运行任务时遇到的任何未捕获异常。然而,我似乎无法让它工作 例如: public class ThreadPoolErrors extends ThreadPoolExecutor { public ThreadPoolErrors() {

我试图使用Java的
ThreadPoolExecutor
类来运行大量具有固定线程数的重载任务。每个任务都有许多地方,在此期间可能会由于异常而失败

我对
ThreadPoolExecutor
进行了子类化,并重写了
afterExecute
方法,该方法应该提供在运行任务时遇到的任何未捕获异常。然而,我似乎无法让它工作

例如:

public class ThreadPoolErrors extends ThreadPoolExecutor {
    public ThreadPoolErrors() {
        super(  1, // core threads
                1, // max threads
                1, // timeout
                TimeUnit.MINUTES, // timeout units
                new LinkedBlockingQueue<Runnable>() // work queue
        );
    }

    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if(t != null) {
            System.out.println("Got an error: " + t);
        } else {
            System.out.println("Everything's fine--situation normal!");
        }
    }

    public static void main( String [] args) {
        ThreadPoolErrors threadPool = new ThreadPoolErrors();
        threadPool.submit( 
                new Runnable() {
                    public void run() {
                        throw new RuntimeException("Ouch! Got an error.");
                    }
                }
        );
        threadPool.shutdown();
    }
}
import com.jcabi.log.VerboseRunnable;
scheduler.scheduleWithFixedDelay(
  new VerboseRunnable(
    Runnable() {
      public void run() { 
        // the code, which may throw
      }
    },
    true // it means that all exceptions will be swallowed and logged
  ),
  1, 1, TimeUnit.MILLISECONDS
);
公共类ThreadPoolErrors扩展ThreadPoolExecutor{
公共线程池错误(){
超级(1,//核心线程
1,//最大线程数
1,//超时
TimeUnit.MINUTES,//超时单位
新建LinkedBlockingQueue()//工作队列
);
}
执行后受保护的无效(可运行的r、可丢弃的t){
super.afterExecute(r,t);
如果(t!=null){
System.out.println(“出现错误:+t”);
}否则{
System.out.println(“一切正常,情况正常!”);
}
}
公共静态void main(字符串[]args){
ThreadPoolErrors threadPool=新的ThreadPoolErrors();
线程池。提交(
新的Runnable(){
公开募捐{
抛出新的RuntimeException(“哎哟!出错了。”);
}
}
);
threadPool.shutdown();
}
}
该程序的输出是“一切正常——情况正常!”,即使提交到线程池的唯一可运行程序抛出异常。这里发生了什么有线索吗

谢谢

警告:应该注意,此解决方案将阻止调用线程


如果要处理任务引发的异常,通常最好使用
Callable
,而不是
Runnable

Callable.call()
允许抛出已检查的异常,这些异常会传播回调用线程:

Callable task = ...
Future future = executor.submit(task);
try {
   future.get();
} catch (ExecutionException ex) {
   ex.getCause().printStackTrace();
}
如果
Callable.call()
引发异常,则该异常将包装在
ExecutionException
中,并由
Future.get()引发


这可能比子类化
ThreadPoolExecutor
要好得多。如果异常是可恢复的,您还可以重新提交任务。

我将为它提供一个创建新线程的实例,并从以下位置为它们提供一个

,而不是子类化ThreadPoolExecutor:

注意:当动作包含在 任务(如FutureTask)或 显式地或通过诸如 提交时,这些任务对象捕获并 维护计算异常,以及 因此,它们不会导致突然的 终止,以及内部 例外情况不会传递给此 方法

当您提交Runnable时,它将被包装在未来

您的afterExecute应该是这样的:

public final class ExtendedExecutor extends ThreadPoolExecutor {

    // ...

    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if (t == null && r instanceof Future<?>) {
            try {
                Future<?> future = (Future<?>) r;
                if (future.isDone()) {
                    future.get();
                }
            } catch (CancellationException ce) {
                t = ce;
            } catch (ExecutionException ee) {
                t = ee.getCause();
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
            }
        }
        if (t != null) {
            System.out.println(t);
        }
    }
}
公共最终类ExtendedExecutor扩展ThreadPoolExecutor{
// ...
执行后受保护的无效(可运行的r、可丢弃的t){
super.afterExecute(r,t);
if(t==null&&r未来实例){
试一试{
未来=(未来)r;
if(future.isDone()){
future.get();
}
}捕获(取消异常){
t=ce;
}捕获(被执行者){
t=ee.getCause();
}捕获(中断异常ie){
Thread.currentThread().interrupt();
}
}
如果(t!=null){
系统输出打印ln(t);
}
}
}

对这种行为的解释如下:

注意:当动作包含在 任务(如FutureTask)或 显式地或通过诸如 提交时,这些任务对象捕获并 维护计算异常,以及 因此,它们不会导致突然的 终止,以及内部 例外情况不会传递给此 方法

我使用的是from类,它会吞并所有异常并记录它们。非常方便,例如:

public class ThreadPoolErrors extends ThreadPoolExecutor {
    public ThreadPoolErrors() {
        super(  1, // core threads
                1, // max threads
                1, // timeout
                TimeUnit.MINUTES, // timeout units
                new LinkedBlockingQueue<Runnable>() // work queue
        );
    }

    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if(t != null) {
            System.out.println("Got an error: " + t);
        } else {
            System.out.println("Everything's fine--situation normal!");
        }
    }

    public static void main( String [] args) {
        ThreadPoolErrors threadPool = new ThreadPoolErrors();
        threadPool.submit( 
                new Runnable() {
                    public void run() {
                        throw new RuntimeException("Ouch! Got an error.");
                    }
                }
        );
        threadPool.shutdown();
    }
}
import com.jcabi.log.VerboseRunnable;
scheduler.scheduleWithFixedDelay(
  new VerboseRunnable(
    Runnable() {
      public void run() { 
        // the code, which may throw
      }
    },
    true // it means that all exceptions will be swallowed and logged
  ),
  1, 1, TimeUnit.MILLISECONDS
);

我通过包装提交给执行人的runnable文件来解决这个问题

CompletableFuture.runAsync(() -> {
        try {
              runnable.run();
        } catch (Throwable e) {
              Log.info(Concurrency.class, "runAsync", e);
        }
}, executorService);

如果您的
ExecutorService
来自外部源(即无法对
ThreadPoolExecutor
子类化并重写
afterExecute()
),则可以使用动态代理来实现所需的行为:

public static ExecutorService errorAware(final ExecutorService executor) {
    return (ExecutorService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
            new Class[] {ExecutorService.class},
            (proxy, method, args) -> {
                if (method.getName().equals("submit")) {
                    final Object arg0 = args[0];
                    if (arg0 instanceof Runnable) {
                        args[0] = new Runnable() {
                            @Override
                            public void run() {
                                final Runnable task = (Runnable) arg0;
                                try {
                                    task.run();
                                    if (task instanceof Future<?>) {
                                        final Future<?> future = (Future<?>) task;

                                        if (future.isDone()) {
                                            try {
                                                future.get();
                                            } catch (final CancellationException ce) {
                                                // Your error-handling code here
                                                ce.printStackTrace();
                                            } catch (final ExecutionException ee) {
                                                // Your error-handling code here
                                                ee.getCause().printStackTrace();
                                            } catch (final InterruptedException ie) {
                                                Thread.currentThread().interrupt();
                                            }
                                        }
                                    }
                                } catch (final RuntimeException re) {
                                    // Your error-handling code here
                                    re.printStackTrace();
                                    throw re;
                                } catch (final Error e) {
                                    // Your error-handling code here
                                    e.printStackTrace();
                                    throw e;
                                }
                            }
                        };
                    } else if (arg0 instanceof Callable<?>) {
                        args[0] = new Callable<Object>() {
                            @Override
                            public Object call() throws Exception {
                                final Callable<?> task = (Callable<?>) arg0;
                                try {
                                    return task.call();
                                } catch (final Exception e) {
                                    // Your error-handling code here
                                    e.printStackTrace();
                                    throw e;
                                } catch (final Error e) {
                                    // Your error-handling code here
                                    e.printStackTrace();
                                    throw e;
                                }
                            }
                        };
                    }
                }
                return method.invoke(executor, args);
            });
}
公共静态执行器服务errorAware(最终执行器服务执行器){
return(ExecutorService)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
新类[]{ExecutorService.Class},
(代理、方法、参数)->{
if(method.getName().equals(“提交”)){
最终对象arg0=args[0];
如果(arg0 instanceof Runnable){
args[0]=新的可运行(){
@凌驾
公开募捐{
最终可运行任务=(可运行)arg0;
试一试{
task.run();
if(未来的任务实例){
最终未来=(未来)任务;
if(future.isDone()){
试一试{
future.get();
}捕获(最终取消异常ce){
//您的错误处理代码在这里
printStackTrace();
}捕获(最终被执行人){
//你的错误
AbstractExecutorService.java

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null); /////////HERE////////
    execute(ftask);
    return ftask;
}
ThreadPoolExecutor.java

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    task.run();           /////////HERE////////
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}
class FutureTask<V> implements RunnableFuture<V>

public void run() {
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {   /////////HERE////////
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}
public final class SingleThreadExecutorWithExceptions { public static ExecutorService newSingleThreadExecutorWithExceptions(final Thread.UncaughtExceptionHandler uncaughtExceptionHandler) { ThreadFactory factory = (Runnable runnable) -> { final Thread newThread = new Thread(runnable, "SingleThreadExecutorWithExceptions"); newThread.setUncaughtExceptionHandler( (final Thread caugthThread,final Throwable throwable) -> { uncaughtExceptionHandler.uncaughtException(caugthThread, throwable); }); return newThread; }; return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), factory){ protected void afterExecute(Runnable runnable, Throwable throwable) { super.afterExecute(runnable, throwable); if (throwable == null && runnable instanceof Future) { try { Future future = (Future) runnable; if (future.isDone()) { future.get(); } } catch (CancellationException ce) { throwable = ce; } catch (ExecutionException ee) { throwable = ee.getCause(); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); // ignore/reset } } if (throwable != null) { uncaughtExceptionHandler.uncaughtException(Thread.currentThread(),throwable); } } }); } private static class FinalizableDelegatedExecutorService extends DelegatedExecutorService { FinalizableDelegatedExecutorService(ExecutorService executor) { super(executor); } protected void finalize() { super.shutdown(); } } /** * A wrapper class that exposes only the ExecutorService methods * of an ExecutorService implementation. */ private static class DelegatedExecutorService extends AbstractExecutorService { private final ExecutorService e; DelegatedExecutorService(ExecutorService executor) { e = executor; } public void execute(Runnable command) { e.execute(command); } public void shutdown() { e.shutdown(); } public List shutdownNow() { return e.shutdownNow(); } public boolean isShutdown() { return e.isShutdown(); } public boolean isTerminated() { return e.isTerminated(); } public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return e.awaitTermination(timeout, unit); } public Future submit(Runnable task) { return e.submit(task); } public Future submit(Callable task) { return e.submit(task); } public Future submit(Runnable task, T result) { return e.submit(task, result); } public List> invokeAll(Collection> tasks) throws InterruptedException { return e.invokeAll(tasks); } public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { return e.invokeAll(tasks, timeout, unit); } public T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException { return e.invokeAny(tasks); } public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return e.invokeAny(tasks, timeout, unit); } } private SingleThreadExecutorWithExceptions() {} }
public abstract Task implements Runnable {

    public abstract void execute();

    public void run() {
      try {
        execute();
      } catch (Throwable t) {
        // handle it  
      }
    }
}


public MySampleTask extends Task {
    public void execute() {
        // heavy, error-prone code here
    }
}