Java 当线程中发生异常时,SchduledExecutorService未执行UncaughtExceptionHandler
我正在使用ScheduledExecutorService,它使用ThreadFactory创建新线程。但是,当计划任务中发生某些异常时,不会执行threadfactory中的UncaughtExceptionHandler。为什么会这样 螺纹工厂如下:Java 当线程中发生异常时,SchduledExecutorService未执行UncaughtExceptionHandler,java,scheduler,scheduledexecutorservice,uncaughtexceptionhandler,Java,Scheduler,Scheduledexecutorservice,Uncaughtexceptionhandler,我正在使用ScheduledExecutorService,它使用ThreadFactory创建新线程。但是,当计划任务中发生某些异常时,不会执行threadfactory中的UncaughtExceptionHandler。为什么会这样 螺纹工厂如下: public class CustomThreadFactory { public static ThreadFactory defaultFactory(String namePrefix) { return new Thread
public class CustomThreadFactory {
public static ThreadFactory defaultFactory(String namePrefix) {
return new ThreadFactoryBuilder()
.setNameFormat(String.format("%s-%%d", namePrefix))
.setDaemon(false)
.setUncaughtExceptionHandler(new CustomExceptionHandler())
.build();
}
}
异常处理程序:
public class CustomExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread thread, Throwable t) {
log.error("Received uncaught exception {}", thread.getName(), t);
}
}
主要功能:
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(
CustomThreadFactory.defaultFactory("scheduler"));
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 20L,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1));
scheduler.scheduleWithFixedDelay(
() -> {
executor.submit(() -> Thread.sleep(10000));
},0,1,TimeUnit.SECONDS);
}
publicstaticvoidmain(字符串[]args){
ScheduleXecutorService scheduler=Executors.NewsingleThreadScheduleXecutor(
CustomThreadFactory.defaultFactory(“调度器”);
ThreadPoolExecutor executor=新的ThreadPoolExecutor(1,1,20L,
TimeUnit.ms,新的LinkedBlockingQueue(1));
scheduler.scheduleWithFixedDelay(
() -> {
executor.submit(()->Thread.sleep(10000));
},0,1,时间单位为秒);
}
我正在陈述我的确切问题,这样它就不会成为XY问题。在上面的代码片段中,阻塞队列的大小为1,任务每秒添加到阻塞队列中。因此,在增加第三项任务时,阻塞队列执行器给出了
RejectionExecutionException
,当线程由于未捕获的异常即将终止时,Java虚拟机将使用thread.getUncaughtExceptionHandler()查询线程的未捕获的异常处理程序
并将调用处理程序的uncaughtException方法,将线程和异常作为参数传递
如果提交的任务引发未捕获异常,但任务本身未引发RejectionExecutionException
,则将调用UncaughtExceptionHandler。但是,您可以将RejectedExecutionHandler
传递给ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
和setException()
方法将异常对象设置为FutureTask
的结果
protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
}
}
现在的问题是,我们能否以某种方式获得异常/异常通知
是的,这是可能的。当您在未来调用Future#get
时,将抛出异常,但是exception
将封装在ExecutionException
中。看看Future#get
方法
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
public V get()抛出InterruptedException、ExecutionException{
int s=状态;
如果(s=取消)
抛出新的CancellationException();
抛出新的ExecutionException((Throwable)x);
}
我在ScheduledThreadPoolExecutor
上看到了所有可用的方法(submit、execute、schedule等),它们将任务包装到未来的任务中。因此,我认为没有办法通过UncaughtExceptionHandler
处理异常
但是,对于ThreadPoolExecutor,如果您使用ThreadPoolExecutor\35; submit
提交任务,您的UncaughtExceptionHandler
将不收到通知,但如果您使用ThreadPoolExecutor\35; execute
则UncaughtExceptionHandler
将收到通知ThreadPoolExecutor#execute
不会将您的任务包装在Future
中 RejectionExecutionException由java.util.concurrent.RejectedExecutionHandler
处理,而不是由UncaughtExceptionHandler
处理,它仅用于任务执行期间引发的异常。ThreadPoolExecutor具有允许您指定自己的RejectedExecutionHandler的构造函数。在本例中,它不是实际的任务executor.submit(()->Thread.sleep(10000))代码>而不仅仅是线程。睡眠(10000)。而RejectionExecutionException是由submit函数抛出的,但我理解它。当JVM遇到RejectionExecutionException时,它不会检查UncaughtExceptionHandler,而只检查RejectionExecutionHandler。@ShashwatKumar我明白你的意思了。我需要更深入地研究代码。如果我发现了什么,我会告诉你的。@ShashwatKumar我已经更新了我的答案。请看一看。我希望它能帮助你。谢谢
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}