首页 > 其他分享 >UncaughtExceptionHandler 是什么?线程池如何处理异常?

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

时间:2022-12-25 15:25:17浏览次数:34  
标签:UncaughtExceptionHandler 捕获 线程 处理器 import 异常

 

 

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

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

UncaughtExceptionHandler 源码(JDK8)

/**
 * 当线程由于未捕获异常而突然终止时调用的处理程序接口。 
 * 当线程由于未捕获异常即将终止时,Java虚拟机将使用getUncaughtExceptionHandler查询线程的
 * UncaughtExceptionHandler,并调用处理程序的uncaughtException方法,将线程和异常作为参数传递。
 * 如果线程未显式设置其UncaughtExceptionHandler,则其ThreadGroup对象将充当其
 * UncaughtExceptionHandler。
 * 如果ThreadGroup对象对处理异常没有特殊要求,它可以将调用转发给默认的未捕获异常处理程序。
 */
public interface UncaughtExceptionHandler {
    /**
     * 方法,该方法在给定线程由于给定的未捕获异常而终止时调用。 
     * Java虚拟机将忽略此方法引发的任何异常。 
     * 参数: 
     * t–线程 
     * e–异常
     */
    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;

/**
 * Factories for {@link UncaughtExceptionHandler} instances.
 *
 * @author Gregory Kick
 * @since 8.0
 */
@GwtIncompatible
public final class UncaughtExceptionHandlers {
  private UncaughtExceptionHandlers() {}

  /**
   * Returns an exception handler that exits the system. This is particularly useful for the main
   * thread, which may start up other, non-daemon threads, but fail to fully initialize the
   * application successfully.
   *
   * <p>Example usage:
   *
   * <pre>
   * public static void main(String[] args) {
   *   Thread.currentThread().setUncaughtExceptionHandler(UncaughtExceptionHandlers.systemExit());
   *   ...
   * </pre>
   *
   * <p>The returned handler logs any exception at severity {@code SEVERE} and then shuts down the
   * process with an exit status of 1, indicating abnormal termination.
   */
  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 中重新抛出。

标签:UncaughtExceptionHandler,捕获,线程,处理器,import,异常
From: https://www.cnblogs.com/shoshana-kong/p/17004056.html

相关文章

  • 线程锁的使用 lock
    importthreadingimporttimelock=threading.Lock()num=0lock=threading.Lock()defplay(name):globalnumforiinrange(100):print(f"{name}正在......
  • 线程安全分析
    线程安全分析成员变量和静态变量是否线程安全?如果它们没有共享,则线程安全如果它们被共享了,根据它们的状态是否能够改变,又分两种情况如果只有读操作,则线程安全如果有......
  • GOQTTemplate3的多线程化改造
      GOQTTemplate3作为一个QT+OpenCV的平台,希望能够为使用者提供基础的跨平台的图像处理框架。图像处理算法和GUI两个线程的隔离,是必然需要的。在之前的版本中,都采用了......
  • linux网络编程-线程——通过信号控制互斥锁
    1//由于pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a,所以在使用pthread_create创建线程时,在编译中要加-lpthread参数2//gccpthread_sig_mutex.c-......
  • linux网络编程-线程创建和退出
    线程创建函数:intpthread_create(pthread_t*thread,constpthread_attr_t*attr,void*(*start_routine)(void*),void*arg);第一个参数thread是出参,传出创建的线程......
  • 让人恶心的多线程代码,性能怎么优化!
    小姐姐味道(微信公众号ID:xjjdog)Java中最烦人的,就是多线程,一不小心,代码写的比单线程还慢,这就让人非常尴尬。通常情况下,我们会使用ThreadLocal实现线程封闭,比如避免SimpleD......
  • Java中的异常、IO与NIO面试题
    ✅作者简介:热爱国学的Java后端开发者,修心和技术同步精进。......
  • 多线程
    多线程什么是进程?什么是线程?进程是一个应用程序(1个进程是一个软件)。线程是一个进程中的执行场景/执行单元。一个进程可以启动多个线程。对于java程序来说,当在DOS命令......
  • linux网络编程-线程间通信——互斥锁
    为了保证线程在执行某段代码时不被其他线程打断,可以使用互斥锁进行保护,而这段被保护的代码区域被称为临界区。原理:线程执行锁定函数pthread_mutex_lock()时,如果锁没有被其......
  • Servlet生命周期和线程安全
    本文目录​​一、Servlet生命周期​​​​1、生命周期四个阶段​​​​1.1、实例化​​​​1.2、初始化​​​​1.3、服务​​​​1.4、销毁​​​​1.5、Servlet执行流程​......