高并发编程-捕获线程运行时的异常 + 获取调用链
生活随笔
收集整理的這篇文章主要介紹了
高并发编程-捕获线程运行时的异常 + 获取调用链
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 概述
- 捕獲線程運行時的異常
- 使用場景
- UncaughtExceptionHandler 接口
- 示例
- 獲取調用鏈
- 使用線程池的場景: 獲取線程運行時異常
概述
捕獲線程運行時的異常
我們看下Thread的定義 實現了Runnable接口
重寫了run方法
根據方法簽名可知,run方法是不能向上層拋出異常的,如果線程內部產生異常, 不catch的情況下,上層調用代碼如何知道呢?
使用場景
為啥需要這樣做呢?
一個線程拋出異常之后,只會在控制臺打印堆棧信息,即使有日志記錄,因為程序捕獲不到異常,只會在控制臺打出,并不是在日志記錄中出現。
所以,除非在線程拋出異常的時候,你剛好在觀察控制臺輸出的日子,看到了堆棧信息,否則,很難找到線程是哪里拋出了異常。
所以上面我們說到的捕獲線程內異常,就有用了,正常情況下,我們捕獲不到線程內的異常,但是我們可以通過 UncaughtExceptionHandler 來進行捕獲異常。并在在Handler中打印出錯誤日志,方便定位排查問題。
UncaughtExceptionHandler 接口
先看下 Thread類中的UncaughtExceptionHandler接口
示例
兩個線程,一個線程一直運行 ,另外一個線程有異常(一個數組下標越界異常,一個OOM異常 )
這里用OOM來演示
JVM參數設置: -Xms10m -Xmx10m
package com.artisan.test;import java.util.ArrayList; import java.util.Arrays; import java.util.List;public class CaughtThreadExceptionDemo {public static void main(String[] args) {List list = Arrays.asList(1, 2, 3);// 模擬線程一 拋出異常 被終止Thread t = new Thread(() -> {try {Thread.sleep(2_000); // list.get(99);List list2 = new ArrayList();for (int i = 0; i < Integer.MAX_VALUE; i++) {list2.add(i + "biubiubiubiubiubiubiubiubiubiubiubiu");}} catch (InterruptedException e) { // 這個地方不要捕獲 ArrayIndexOutOfBoundsException ,否則setUncaughtExceptionHandler無法捕獲到該異常System.out.println(Thread.currentThread().getName() + " some error happened....");e.printStackTrace();}}, "TEST_THREAD_1");// 線程啟動之前setUncaughtExceptionHandlert.setUncaughtExceptionHandler((thread, e) -> {System.out.println(" UncaughtExceptionHandler handle...." + e);System.out.println(" UncaughtExceptionHandler handle...." + thread.getName());});t.start();// 線程二 一直運行new Thread(() -> {while (true) {try {Thread.sleep(10_000);System.out.println(Thread.currentThread().getName() + " working...");} catch (InterruptedException e) {e.printStackTrace();}}}, "TEST_THREAD_2").start();} }輸出
注意事項
獲取調用鏈
假設線程拋出如上異常,我們想記錄下更多的信息到DB或者其他存儲介質中,那如何打印出類似上面的信息呢?
答案就是: getStackTrace() ,然后把它的輸出獲取出來 。
示例如下:
package com.artisan.test;import java.util.Arrays; import java.util.Optional;public class StackTraceDemo {public static void main(String[] args) {Test1 test1 = new Test1();test1.test1();}static class Test1 {public void test1() {new Test2().test2();}}static class Test2 {public void test2() {// Thread.currentThread().getStackTrace() 數組 轉 List// List stream ,然后過濾掉本地方法,最后遍歷 輸出Arrays.asList(Thread.currentThread().getStackTrace()).stream()// 過濾掉native方法.filter(element -> !element.isNativeMethod()).forEach(element -> Optional.of(element.getClassName() + ":" + element.getMethodName() + ":" + element.getLineNumber()).ifPresent(System.out::println));}} }輸出如下:
使用線程池的場景: 獲取線程運行時異常
戳這里
總結
以上是生活随笔為你收集整理的高并发编程-捕获线程运行时的异常 + 获取调用链的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高并发编程-Runtime.getRun
- 下一篇: 高并发编程-自定义简易的线程池(1),体