Java中如何从当前线程中捕获并获取异常详情?

2026-05-26 00:532阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1160个文字,预计阅读时间需要5分钟。

Java中如何从当前线程中捕获并获取异常详情?

目录 + Java主动从当前线程获取异常信息 + 使用场景 + 写法 + Java捕获并处理线程异常:Thread异常捕获 + 通过Thread.UncaughtExceptionHandler捕获线程异常 + ThreadPoolExecutor线程池异常捕获

目录
  • Java主动从当前线程获取异常信息
    • 使用场景
    • 写法
  • Java捕获并处理线程异常:Thread及ThreadPoolExecutor线程池异常捕获
    • 通过Thread.UncaughtExceptionHandler捕获线程异常
    • ThreadPoolExecutor线程池异常捕获

Java主动从当前线程获取异常信息

使用场景

在单个方法内主动捕获异常,并将异常的错误栈信息以日志的方式打出来

写法

当前方法throw 了 异常,即改方法存在异常的情况,则可以使用如下方式获取当前线程中的异常:

// 主动获取当前线程异常栈信息 StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); // 以日志的方式打出  \n  每一行错误栈信息结束后换行 log.error(StringUtils.join(stackTraceElements, '\n'));

Java捕获并处理线程异常:Thread及ThreadPoolExecutor线程池异常捕获

通过Thread.UncaughtExceptionHandler捕获线程异常

Thread.UncaughtExceptionHandler类的作用:捕获并处理线程run方法抛出的异常。

使用示例

为单个线程设置异常捕获

Thread.UncaughtExceptionHandler exceptionHandler = (t, e) -> {     System.out.println("报错线程:" + t.getName());     System.out.println("线程抛出的异常:" + e); }; Thread thread = new Thread(() -> {     throw new RuntimeException("throw a new Exception ! "); }); thread.setUncaughtExceptionHandler(exceptionHandler); // 设置异常处理器 thread.start();

如果项目中,全局的Thread线程处理异常的方式都相同,那么可以设置一个全局的异常捕获类。

Thread.UncaughtExceptionHandler exceptionHandler = (t, e) -> {     System.out.println("报错线程:" + t.getName());     System.out.println("线程抛出的异常:" + e); }; Thread.setDefaultUncaughtExceptionHandler(exceptionHandler);

通过这种方式,后续的Thread都可以公用这个异常处理类。如果需要用其它方式处理异常时,只需要实现1中的内容即可。

部分源码解析

UncaughtExceptionHandler源码 // Thread.UncaughtExceptionHandler  @FunctionalInterface public interface UncaughtExceptionHandler {     void uncaughtException(Thread t, Throwable e); }

Thread中的UncaughtExceptionHandler属性

Java中如何从当前线程中捕获并获取异常详情?

// 作用于当个Thread线程 private volatile UncaughtExceptionHandler uncaughtExceptionHandler; // static修饰,其可以作用于所有Thread线程 private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;

在Thread中,会首先提供Thread私有的异常处理类,然后才是全局

public UncaughtExceptionHandler getUncaughtExceptionHandler() {     return uncaughtExceptionHandler != null ?         uncaughtExceptionHandler : group; }

实现原理

当线程由于未捕获的异常而即将终止时,Java虚拟机将使用调用线程的getUncaughtExceptionHandler方法,以此来获取UncaughtExceptionHandler类,并执行其对异常的处理方法。

如果一个线程没有显式实现UncaughtExceptionHandler ,那么它的ThreadGroup对象将充当它的UncaughtExceptionHandler类。

// Thread#getUncaughtExceptionHandler public UncaughtExceptionHandler getUncaughtExceptionHandler() {     return uncaughtExceptionHandler != null ?         uncaughtExceptionHandler : group; }

ThreadGroup实现了UncaughtExceptionHandler类。

public class ThreadGroup implements Thread.UncaughtExceptionHandler {     // ……     public void uncaughtException(Thread t, Throwable e) {         // 父级ThreadGroup的处理方法         if (parent != null) {             parent.uncaughtException(t, e);         } else {             // Thread 的全局默认处理方法             Thread.UncaughtExceptionHandler ueh =                 Thread.getDefaultUncaughtExceptionHandler();             if (ueh != null) {                 ueh.uncaughtException(t, e);             } else if (!(e instanceof ThreadDeath)) {                 System.err.print("Exception in thread \""                                  + t.getName() + "\" ");                 e.printStackTrace(System.err);             }         }     }     // …… }

ThreadPoolExecutor线程池异常捕获

使用示例

要捕获ThreadPoolExecutor线程池中的线程执行异常,需要实现被protected修饰的方法afterExecute,在该方法里面处理异常即可。

// ThreadPoolExecutor#afterExecute class ExtendedExecutor extends ThreadPoolExecutor {   protected void afterExecute(Runnable r, Throwable t) {     super.afterExecute(r, t);     // 如果Runnable是Future类型,那么异常将会直接通过Future返回     if (t == null && r instanceof Future<?>) {       try {         Object result = ((Future<?>) r).get();       } catch (CancellationException ce) {           t = ce;       } catch (ExecutionException ee) {           t = ee.getCause();       } catch (InterruptedException ie) {           Thread.currentThread().interrupt(); // ignore/reset       }     }     // 非Future类型     if (t != null)       System.out.println(t);   } }

注意:实现afterExecute方法时,要正确嵌套多个覆盖,子类通常应在此方法的开头调用super.afterExecute,以确保不会破坏其他父类方法的实现。

源码解析

在ThreadPoolExecutor中,线程任务的实际执行方法是runWorker,如下所示:

// ThreadPoolExecutor#runWorker final void runWorker(Worker w) {     Thread wt = Thread.currentThread();     Runnable task = w.firstTask; // 实际提交的任务             // …………             try {                 beforeExecute(wt, task); // task执行前的操作                 Throwable thrown = null; // 异常信息保存                 try {                     task.run(); // 执行任务                 } catch (RuntimeException x) {                     thrown = x; throw x;                 } catch (Error x) {                     thrown = x; throw x;                 } catch (Throwable x) {                     thrown = x; throw new Error(x);                 } finally {                     afterExecute(task, thrown); // task执行后的操作,也就包括了异常的捕获工作                 }             } finally {                 task = null;                 w.completedTasks++;                 w.unlock();             }         // …… }

afterExecute方法在ThreadPoolExecutor,并没有进行任何操作,就是对异常的线程静默处理

// ThreadPoolExecutor#afterExecute protected void afterExecute(Runnable r, Throwable t) { }

Callable类型的任务,在执行时会自己捕获并维护执行中的异常。

// AbstractExecutorService#submit public <T> Future<T> submit(Callable<T> task) {     if (task == null) throw new NullPointerException();     RunnableFuture<T> ftask = newTaskFor(task);     execute(ftask);     return ftask; } // Callable任务会被封装成FutureTask protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {     return new FutureTask<T>(callable); }

在FutureTask的run方法中,他们内部会将整个任务用try-catch给包起来。因此,也不会抛出Callable#run执行的内部异常。

// FutureTask#run public void run() {     // ……     try {         Callable<V> c = callable;         // ……             // 这里将Callable的执行过程产生的异常都捕获了             try {                 result = c.call();                 ran = true;             } catch (Throwable ex) {                 result = null;                 ran = false;                 setException(ex);             }             if (ran)                 set(result);         }     } finally { // ……

以上为个人经验,希望能给大家一个参考,也希望大家多多支持自由互联。

本文共计1160个文字,预计阅读时间需要5分钟。

Java中如何从当前线程中捕获并获取异常详情?

目录 + Java主动从当前线程获取异常信息 + 使用场景 + 写法 + Java捕获并处理线程异常:Thread异常捕获 + 通过Thread.UncaughtExceptionHandler捕获线程异常 + ThreadPoolExecutor线程池异常捕获

目录
  • Java主动从当前线程获取异常信息
    • 使用场景
    • 写法
  • Java捕获并处理线程异常:Thread及ThreadPoolExecutor线程池异常捕获
    • 通过Thread.UncaughtExceptionHandler捕获线程异常
    • ThreadPoolExecutor线程池异常捕获

Java主动从当前线程获取异常信息

使用场景

在单个方法内主动捕获异常,并将异常的错误栈信息以日志的方式打出来

写法

当前方法throw 了 异常,即改方法存在异常的情况,则可以使用如下方式获取当前线程中的异常:

// 主动获取当前线程异常栈信息 StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); // 以日志的方式打出  \n  每一行错误栈信息结束后换行 log.error(StringUtils.join(stackTraceElements, '\n'));

Java捕获并处理线程异常:Thread及ThreadPoolExecutor线程池异常捕获

通过Thread.UncaughtExceptionHandler捕获线程异常

Thread.UncaughtExceptionHandler类的作用:捕获并处理线程run方法抛出的异常。

使用示例

为单个线程设置异常捕获

Thread.UncaughtExceptionHandler exceptionHandler = (t, e) -> {     System.out.println("报错线程:" + t.getName());     System.out.println("线程抛出的异常:" + e); }; Thread thread = new Thread(() -> {     throw new RuntimeException("throw a new Exception ! "); }); thread.setUncaughtExceptionHandler(exceptionHandler); // 设置异常处理器 thread.start();

如果项目中,全局的Thread线程处理异常的方式都相同,那么可以设置一个全局的异常捕获类。

Thread.UncaughtExceptionHandler exceptionHandler = (t, e) -> {     System.out.println("报错线程:" + t.getName());     System.out.println("线程抛出的异常:" + e); }; Thread.setDefaultUncaughtExceptionHandler(exceptionHandler);

通过这种方式,后续的Thread都可以公用这个异常处理类。如果需要用其它方式处理异常时,只需要实现1中的内容即可。

部分源码解析

UncaughtExceptionHandler源码 // Thread.UncaughtExceptionHandler  @FunctionalInterface public interface UncaughtExceptionHandler {     void uncaughtException(Thread t, Throwable e); }

Thread中的UncaughtExceptionHandler属性

Java中如何从当前线程中捕获并获取异常详情?

// 作用于当个Thread线程 private volatile UncaughtExceptionHandler uncaughtExceptionHandler; // static修饰,其可以作用于所有Thread线程 private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;

在Thread中,会首先提供Thread私有的异常处理类,然后才是全局

public UncaughtExceptionHandler getUncaughtExceptionHandler() {     return uncaughtExceptionHandler != null ?         uncaughtExceptionHandler : group; }

实现原理

当线程由于未捕获的异常而即将终止时,Java虚拟机将使用调用线程的getUncaughtExceptionHandler方法,以此来获取UncaughtExceptionHandler类,并执行其对异常的处理方法。

如果一个线程没有显式实现UncaughtExceptionHandler ,那么它的ThreadGroup对象将充当它的UncaughtExceptionHandler类。

// Thread#getUncaughtExceptionHandler public UncaughtExceptionHandler getUncaughtExceptionHandler() {     return uncaughtExceptionHandler != null ?         uncaughtExceptionHandler : group; }

ThreadGroup实现了UncaughtExceptionHandler类。

public class ThreadGroup implements Thread.UncaughtExceptionHandler {     // ……     public void uncaughtException(Thread t, Throwable e) {         // 父级ThreadGroup的处理方法         if (parent != null) {             parent.uncaughtException(t, e);         } else {             // Thread 的全局默认处理方法             Thread.UncaughtExceptionHandler ueh =                 Thread.getDefaultUncaughtExceptionHandler();             if (ueh != null) {                 ueh.uncaughtException(t, e);             } else if (!(e instanceof ThreadDeath)) {                 System.err.print("Exception in thread \""                                  + t.getName() + "\" ");                 e.printStackTrace(System.err);             }         }     }     // …… }

ThreadPoolExecutor线程池异常捕获

使用示例

要捕获ThreadPoolExecutor线程池中的线程执行异常,需要实现被protected修饰的方法afterExecute,在该方法里面处理异常即可。

// ThreadPoolExecutor#afterExecute class ExtendedExecutor extends ThreadPoolExecutor {   protected void afterExecute(Runnable r, Throwable t) {     super.afterExecute(r, t);     // 如果Runnable是Future类型,那么异常将会直接通过Future返回     if (t == null && r instanceof Future<?>) {       try {         Object result = ((Future<?>) r).get();       } catch (CancellationException ce) {           t = ce;       } catch (ExecutionException ee) {           t = ee.getCause();       } catch (InterruptedException ie) {           Thread.currentThread().interrupt(); // ignore/reset       }     }     // 非Future类型     if (t != null)       System.out.println(t);   } }

注意:实现afterExecute方法时,要正确嵌套多个覆盖,子类通常应在此方法的开头调用super.afterExecute,以确保不会破坏其他父类方法的实现。

源码解析

在ThreadPoolExecutor中,线程任务的实际执行方法是runWorker,如下所示:

// ThreadPoolExecutor#runWorker final void runWorker(Worker w) {     Thread wt = Thread.currentThread();     Runnable task = w.firstTask; // 实际提交的任务             // …………             try {                 beforeExecute(wt, task); // task执行前的操作                 Throwable thrown = null; // 异常信息保存                 try {                     task.run(); // 执行任务                 } catch (RuntimeException x) {                     thrown = x; throw x;                 } catch (Error x) {                     thrown = x; throw x;                 } catch (Throwable x) {                     thrown = x; throw new Error(x);                 } finally {                     afterExecute(task, thrown); // task执行后的操作,也就包括了异常的捕获工作                 }             } finally {                 task = null;                 w.completedTasks++;                 w.unlock();             }         // …… }

afterExecute方法在ThreadPoolExecutor,并没有进行任何操作,就是对异常的线程静默处理

// ThreadPoolExecutor#afterExecute protected void afterExecute(Runnable r, Throwable t) { }

Callable类型的任务,在执行时会自己捕获并维护执行中的异常。

// AbstractExecutorService#submit public <T> Future<T> submit(Callable<T> task) {     if (task == null) throw new NullPointerException();     RunnableFuture<T> ftask = newTaskFor(task);     execute(ftask);     return ftask; } // Callable任务会被封装成FutureTask protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {     return new FutureTask<T>(callable); }

在FutureTask的run方法中,他们内部会将整个任务用try-catch给包起来。因此,也不会抛出Callable#run执行的内部异常。

// FutureTask#run public void run() {     // ……     try {         Callable<V> c = callable;         // ……             // 这里将Callable的执行过程产生的异常都捕获了             try {                 result = c.call();                 ran = true;             } catch (Throwable ex) {                 result = null;                 ran = false;                 setException(ex);             }             if (ran)                 set(result);         }     } finally { // ……

以上为个人经验,希望能给大家一个参考,也希望大家多多支持自由互联。