货币线程池捕获所有异常,然后放置在 Future 对象中供您检查。UncaughtExceptionHandler
仅针对线程未捕获并杀死线程的异常,在这种情况下仅针对线程池代码引发的异常。
解决此问题的一种简单方法是包装您的可运行文件。
public class ExceptionHandlingScheduledExecutor extends ScheduledThreadPoolExecutor {
private final Thread.UncaughtExceptionHandler ueh;
public ExceptionHandlingScheduledExecutor(int corePoolSize, Thread.UncaughtExceptionHandler ueh) {
super(corePoolSize);
this.ueh = ueh;
}
@Override
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
return super.schedule(wrap(command), delay, unit);
}
@Override
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
return super.schedule(wrap(callable), delay, unit);
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
return super.scheduleAtFixedRate(wrap(command), initialDelay, period, unit);
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
return super.scheduleWithFixedDelay(wrap(command), initialDelay, delay, unit);
}
@Override
public void execute(Runnable command) {
super.execute(wrap(command));
}
@Override
public Future<?> submit(Runnable task) {
return super.submit(wrap(task));
}
@Override
public <T> Future<T> submit(Runnable task, T result) {
return super.submit(wrap(task), result);
}
@Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(wrap(task));
}
private Runnable wrap(final Runnable runnable) {
return new Runnable() {
@Override
public void run() {
try {
runnable.run();
} catch (final Throwable t) {
ueh.uncaughtException(Thread.currentThread(), t);
throw t;
}
}
};
}
private <T> Callable<T> wrap(final Callable<T> callable) {
return new Callable<T>() {
@Override
public T call() throws Exception {
try {
return callable.call();
} catch (Throwable t) {
ueh.uncaughtException(Thread.currentThread(), t);
throw t;
}
}
};
}
}
您可以对 ThreadPoolExecutor 进行子类化以透明地执行此操作。
您也可以使用缓存线程池来处理异常,但这更复杂。
以透明方式使用返回Future
的一种方法是子类ScheduledThreadPoolExecutor
(或任何 Executor,就此而言):
class MyScheduledExecutor extends ScheduledThreadPoolExecutor {
private final Thread.UncaughtExceptionHandler ueh;
private final ExecutorService futureService = Executors.newCachedThreadPool();
public MyScheduledExecutor(int corePoolSize, Thread.UncaughtExceptionHandler ueh) {
super(corePoolSize);
this.ueh = ueh;
}
// Copy other constructors
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit) {
final ScheduledFuture<?> f = super.scheduleWithFixedDelay(command, initialDelay, delay, unit);
futureService.submit(new Runnable() {
@Override
public void run() {
try {
f.get();
} catch (Throwable t ) {
ueh.uncaughtException(null, t.getCause());
}
}
};
return f;
}
// Do similarly for other submit/schedule methods
}
并像这样使用它:
final ScheduledThreadPoolExecutor exec = new MyScheduledExecutor(1, new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(final Thread t, final Throwable e) {
e.printStackTrace();
}
});
现在输出如所愿:
Reached 1
Reached 2
Reached 3
Reached 4
Reached 5
java.lang.ArrayIndexOutOfBoundsException: Runtime error!
...