gpt4 book ai didi

java - 当线程中发生异常时,SchduledExecutorService 不执行 UncaughtExceptionHandler

转载 作者:太空宇宙 更新时间:2023-11-04 09:21:00 25 4
gpt4 key购买 nike

我正在使用 ScheduledExecutorService,它使用 ThreadFactory 创建新线程。但是当计划任务发生异常时,threadfactory中的UncaughtExceptionHandler就不会被执行。为什么会发生这种情况?

线程工厂如下:

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);
}

我正在陈述我的确切问题,这样它就不会最终成为 XY 问题。在上面的代码片段中,阻塞队列的大小为一,并且每秒都会将任务添加到阻塞队列中。因此,在添加第三个任务时,阻塞队列执行器会给出 RejectionExecutionException,而 UncaughtExceptionHandler 不会打印该异常。

最佳答案

当线程由于未捕获的异常而即将终止时,Java 虚拟机将查询该线程的 UncaughtExceptionHandler使用 Thread.getUncaughtExceptionHandler() 并将调用处理程序的 uncaughtException 方法,并将线程和异常作为参数传递。

如果提交的任务抛出未捕获的异常,则会调用UncaughtExceptionHandler,但 RejectionExecutionException不会被任务本身抛出。不过,您可以通过RejectedExecutionHandlerThreadPoolExecutor .

    public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}

ThreadPoolExecutor 需要 RejectedExecutionHandler作为一个论点。

编辑:

就您而言UncaughtExceptionHandler不会被调用/通知,因为当您调用 scheduleWithFixedDelay 时不直接执行您的 Runnable,但它会在 ScheduledFutureTask 中扭曲它。 。现在当executor.submit(() -> Thread.sleep(10000));抛出异常(在您的情况下 RejectionExecutionException )它不会保持未捕获状态,因为 FutureTask#run捕获异常并将异常设置为 future 结果/结果。看FutureTask#run的部分:

try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}

setException()方法将异常对象设置为 outcomeFutureTask

protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
}
}

现在的问题是我们能以某种方式获得异常/异常通知吗?

是的,这是可能的。当您调用 Future#get在 Future 上,将会抛出异常,但是 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);
}

我已经在 ScheduledThreadPoolExecutor 上看到了所有可用的方法(提交、执行、计划等)包裹task在未来的任务中。所以我觉得万一出现异常是没有办法通过UncaughtExceptionHandler

但是在 ThreadPoolExecutor 的情况下,如果您使用 ThreadPoolExecutor#submit 提交任务你的UncaughtExceptionHandler不会收到通知,但如果您使用ThreadPoolExecutor#execute然后UncaughtExceptionHandler将被通知为 ThreadPoolExecutor#execute不会将您的任务包装在 Future 中。

关于java - 当线程中发生异常时,SchduledExecutorService 不执行 UncaughtExceptionHandler,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58318817/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com