高并发编程-捕获线程运行时的异常 + 获取调用链

简介: 高并发编程-捕获线程运行时的异常 + 获取调用链

20191031000749801.png


概述


网络异常,图片无法展示
|


捕获线程运行时的异常


我们看下Thread的定义 实现了Runnable接口


20191018162720919.png


重写了run方法


20191018162656758.png


20191018162743618.png


根据方法签名可知,run方法是不能向上层抛出异常的,如果线程内部产生异常, 不catch的情况下,上层调用代码如何知道呢?


使用场景


为啥需要这样做呢?


一个线程抛出异常之后,只会在控制台打印堆栈信息,即使有日志记录,因为程序捕获不到异常,只会在控制台打出,并不是在日志记录中出现。


所以,除非在线程抛出异常的时候,你刚好在观察控制台输出的日子,看到了堆栈信息,否则,很难找到线程是哪里抛出了异常。


所以上面我们说到的捕获线程内异常,就有用了,正常情况下,我们捕获不到线程内的异常,但是我们可以通过 UncaughtExceptionHandler 来进行捕获异常。并在在Handler中打印出错误日志,方便定位排查问题。


UncaughtExceptionHandler 接口


先看下 Thread类中的UncaughtExceptionHandler接口


20191018163142122.png

示例


两个线程,一个线程一直运行 ,另外一个线程有异常(一个数组下标越界异常,一个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();
    }
}


输出


20191018163543666.png

注意事项

  1. 要处理的异常,不要被run方法中的catch捕获(如果有catch的话)
  2. setUncaughtExceptionHandler 在 start之前调用

获取调用链

20191018164332482.png

假设线程抛出如上异常,我们想记录下更多的信息到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));
        }
    }
}


输出如下:


20191018164627106.png


使用线程池的场景: 获取线程运行时异常

戳这里

相关文章
|
7月前
|
人工智能 安全 调度
Python并发编程之线程同步详解
并发编程在Python中至关重要,线程同步确保多线程程序正确运行。本文详解线程同步机制,包括互斥锁、信号量、事件、条件变量和队列,探讨全局解释器锁(GIL)的影响及解决线程同步问题的最佳实践,如避免全局变量、使用线程安全数据结构、精细化锁的使用等。通过示例代码帮助开发者理解并提升多线程程序的性能与可靠性。
242 0
|
9月前
|
Java 开发者 Kotlin
华为仓颉语言初识:并发编程之线程的基本使用
本文详细介绍了仓颉语言中线程的基本使用,包括线程创建(通过`spawn`关键字)、线程名称设置、线程执行控制(使用`get`方法阻塞主线程以获取子线程结果)以及线程取消(通过`cancel()`方法)。文章还指出仓颉线程与Java等语言的差异,例如默认不提供线程名称。掌握这些内容有助于开发者高效处理并发任务,提升程序性能。
295 2
|
4月前
|
Java 测试技术 API
【JUC】(1)带你重新认识进程与线程!!让你深层次了解线程运行的睡眠与打断!!
JUC是什么?你可以说它就是研究Java方面的并发过程。本篇是JUC专栏的第一章!带你了解并行与并发、线程与程序、线程的启动与休眠、打断和等待!全是干货!快快快!
709 2
|
5月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
|
8月前
|
机器学习/深度学习 监控 算法
局域网行为监控软件 C# 多线程数据包捕获算法:基于 KMP 模式匹配的内容分析优化方案探索
本文探讨了一种结合KMP算法的多线程数据包捕获与分析方案,用于局域网行为监控。通过C#实现,该系统可高效检测敏感内容、管理URL访问、分析协议及审计日志。实验表明,相较于传统算法,KMP在处理大规模网络流量时效率显著提升。未来可在算法优化、多模式匹配及机器学习等领域进一步研究。
229 0
|
12月前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
709 14
|
12月前
|
缓存 监控 安全
高并发编程知识体系
本文将从线程的基础理论谈起,逐步探究线程的内存模型,线程的交互,线程工具和并发模型的发展。扫除关于并发编程的诸多模糊概念,从新构建并发编程的层次结构。
|
监控 Java
捕获线程执行异常的多种方法
【10月更文挑战第15天】捕获线程执行异常的方法多种多样,每种方法都有其特点和适用场景。在实际开发中,需要根据具体情况选择合适的方法或结合多种方法来实现全面有效的线程异常捕获。这有助于提高程序的健壮性和稳定性,减少因线程异常带来的潜在风险。
317 57
|
安全 Java 程序员
面试直击:并发编程三要素+线程安全全攻略!
并发编程三要素为原子性、可见性和有序性,确保多线程操作的一致性和安全性。Java 中通过 `synchronized`、`Lock`、`volatile`、原子类和线程安全集合等机制保障线程安全。掌握这些概念和工具,能有效解决并发问题,编写高效稳定的多线程程序。
375 11
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
882 6

热门文章

最新文章