栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

UncaughtExceptionHandler 是什么?线程池如何处理异常?

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

UncaughtExceptionHandler 是什么?线程池如何处理异常?

前言

本文隶属于专栏《100个问题搞定Java并发》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和参考文献请见100个问题搞定Java并发

正文 UncaughtExceptionHandler

在 Thread API 中提供了 UncaughtExceptionHandler ,它能检测出某个线程由于未捕获的异常而终结的情况,能有效地防止线程泄漏问题当一个线程由于未捕获异常而退出时, JVM 会把这个事件报告给应用程序提供的 UncaughtExceptionHandler 异常处理器。

如果没有提供任何异常处理器,那么默认的行为是将梭追踪信息输出到 System.err 。

UncaughtExceptionHandler 源码(JDK8)
public interface UncaughtExceptionHandler {
    
    void uncaughtException(Thread t, Throwable e);
 }

异常处理器如何处理未捕获异常,取决于对服务质量的需求。

最常见的响应方式是将个错误信息以及相应的栈追踪信息写入应用程序日志中。

异常处理器还可以采取更直接的响应,例如尝试重新启动线程,关闭应用程序,或者执行其他修复或诊断等操作。

Guava

下面这段代码来自 Guava(23.0) 包,大家可以参考:

package com.google.common.util.concurrent;

import static java.util.logging.Level.SEVERE;

import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Locale;
import java.util.logging.Logger;


@GwtIncompatible
public final class UncaughtExceptionHandlers {
  private UncaughtExceptionHandlers() {}

  
  public static UncaughtExceptionHandler systemExit() {
    return new Exiter(Runtime.getRuntime());
  }

  @VisibleForTesting
  static final class Exiter implements UncaughtExceptionHandler {
    private static final Logger logger = Logger.getLogger(Exiter.class.getName());

    private final Runtime runtime;

    Exiter(Runtime runtime) {
      this.runtime = runtime;
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
      try {
        // cannot use FormattingLogger due to a dependency loop
        logger.log(
            SEVERE, String.format(Locale.ROOT, "Caught an exception in %s.  Shutting down.", t), e);
      } catch (Throwable errorInLogging) {
        // If logging fails, e.g. due to missing memory, at least try to log the
        // message and the cause for the failed logging.
        System.err.println(e.getMessage());
        System.err.println(errorInLogging.getMessage());
      } finally {
        runtime.exit(1);
      }
    }
  }
}
总结

在运行时间较长的应用程序中,通常会为所有线程的未捕获异常指定同一个异常处理器,并且该处理器至少会将异常信息记录到日志中。

要为线程池中的所有线程设置一个 UncaughtExceptionHandler ,需要为 ThreadPoolExecutor 的构造函数提供一个 ThreadFactory 。 (与所有的线程操控一样,只有线程的所有者能够改变线程的 UncaughtExceptionHandler )

标准线程池允许当发生未捕获异常时结束线程,但由于使用了一个 try – finally 代码块来接收通知,因此当线程结東时,将有新的线程来代替它。

如果没有提供捕获异常处理器或者其他的故障通知机制,那么任务会悄悄失败,从而导致极大的混乱。

如果你希望在任务由于发生异常而失败时获得通知,并且执行一些特定于任务的恢复操作,那么可以将任务封装在能捕获异常的 Runnable 或 Callable 中,或者改写 ThreadPoolExecutor 的 afterExecute 方法。

令人困惑的是,只有通过 execute 提交的任务,才能将它抛出的异常交给未捕获异常处理器,而通过 submit 提交的任务,无论是抛出的未检査异常还是已检査异常,都将被认为是任务返回状态的一部分。

如果一个由 submit 提交的任务由于抛出了异常而结束,那么这个异常将被 Future.get 封装在 ExecutionException 中重新抛出。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/459749.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号