高并发编程-捕获线程运行时的异常 + 获取调用链
概述
捕获线程运行时的异常
我们看下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");
// 线程启动之前setUncaughtExceptionHandler
t.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();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
输出
注意事项
- 要处理的异常,不要被run方法中的catch捕获(如果有catch的话)
- setUncaughtExceptionHandler 在 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));
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
输出如下:
使用线程池的场景: 获取线程运行时异常
文章来源: artisan.blog.csdn.net,作者:小小工匠,版权归原作者所有,如需转载,请联系作者。
原文链接:artisan.blog.csdn.net/article/details/102624708
- 点赞
- 收藏
- 关注作者
评论(0)