java 多线程异常处理

简介: 本文介绍了Java中ThreadGroup的异常处理机制,重点讲解UncaughtExceptionHandler的使用。通过示例代码展示了当线程的run()方法抛出未捕获异常时,JVM如何依次查找并调用线程的异常处理器、线程组的uncaughtException方法或默认异常处理器。文章还提供了具体代码和输出结果,帮助理解不同处理器的优先级与执行逻辑。

ThreadGroup的异常

UncaughtExceptinoHandler

代码解读

复制代码

public static void main(String[] args) {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            int x = 1 / 0;
        }
    };


    Thread thd = new Thread(r);
    thd.start();
}

默认主线程创建了一个尝试除0而故意抛出ArithmeticException对象的runnable


       按照下面的方式编译清单

       javac ExceptionThread.java

       运行程序

       java ExceptionThread

你会看到类ArithmeticException的实例抛出的一条异常栈信息:

代码解读

复制代码

Exception in thread "Thread-0" java.lang.ArithmeticException: / by zero
            at ExceptionThread$1.run(ExceptionThread.java)
            at java.lang.Thread.run(Thread.java:745)

一旦run()方法抛出异常,线程就会中止并被下列活动取代:

  • java虚拟机(JVM)寻找Thread.UncaughtExceptionHandler的实例,该实例有Thread的void set UncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)方法设置。当找到这个handler时,线程就会执行他的void uncaughtException(Thread t, Throwable e)方法,这里t代表了抛出异常线程所关联的Thread对象,而e代表了被抛出的异常或者错误本身--可能会抛出一个java.lang.OutOfMemoryError对象,如果uncaughtException()抛出了一个异常或错误,这个异常或者错误会被JVM忽略。
  • 假设setUncaughtExceptionHandler()未经过调用,JVM就会把控制权给线程关联的ThreadGroup对象上的uncaughtException(Thread t, Throwable e)方法。假设这个ThreadGroup没被继承且uncaughtException方法没有被重写,那么此时若其父ThreadGroup存在,uncaughtException()又会把控制权移交给其父ThreadGroup的uncaughtException()方法。否则,就检查默认的未捕获异常处理器是否已经被设置(通过Thread的static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExcetpionHandler handler)方法)。如果默认未捕获异常处理器已经被设置过,其uncaughtException方法就会被传入相同的两个参数进行调用。反之,uncaughtException()方法检查其Throwable参数是否为java.lang.ThreadDeath的实例。如果是,就没什么特别的了。否则就像清单4-1中异常消息显示的那样,一条包含了线程名称和错误栈的消息就被打印到标准错误流中,线程名称返回子该线程的getname()方法,错误栈出自Throwable栈的printStackTrace()的方法。

    清单4-2演示了Thread的setUncaughtExceptionHandler()和setDefaultcaughtExceptionHandler()方法。

         清单4-2 未捕获异常处理器示例

代码解读

复制代码

public class ExceptinoThread {

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                int x = 1 / 0;
            }
        };


        Thread thd = new Thread(r);
        Thread.UncaughtExceptionHandler uceh;

        uceh = new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {

                System.out.println("Caught throwable" + e + "for thread" + t);
            }
        };

        thd.setUncaughtExceptionHandler(uceh);

        uceh = new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("Default uncaught exception handler");
                System.out.println("Caught throwable" + e + "for thread" + t);
            }
        };
        thd.setDefaultUncaughtExceptionHandler(uceh);
        thd.start();

    }
}

     编译清单4-2(javac ExceptionThread.java),并运行最终程序(java ExceptionThread)。你应该能观测到这样的输出:

代码解读

复制代码

Caught throwablejava.lang.ArithmeticException: / by zerofor threadThread[Thread-0,5,main]

     因为默认的处理器并未调用,你看不到它的输出。想要看到那样的输出,你必须注释掉thd.setUncaughtExceptionHandler(uceh);这行。如果你也注释掉了thd.setDefaultUncaughtExceptionHandler(uceh);这行,那么你就会看到原本清单4-1中的输出。


转载来源:https://juejin.cn/post/6844903652851728392

目录
打赏
0
1
1
0
192
分享
相关文章
Java异常处理:写出更健壮的代码
Java异常处理:写出更健壮的代码
132 0
|
1月前
|
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
84 0
Java 无锁方式实现高性能线程实战操作指南
本文深入探讨了现代高并发Java应用中单例模式的实现方式,分析了传统单例(如DCL)的局限性,并提出了多种无锁实现方案。包括基于ThreadLocal的延迟初始化、VarHandle原子操作、Record不可变对象、响应式编程(Reactor)以及CDI依赖注入等实现方式。每种方案均附有代码示例及适用场景,同时通过JMH性能测试对比各实现的优劣。最后,结合实际案例设计了一个高性能配置中心,展示了无锁单例在实际开发中的应用。总结中提出根据场景选择合适的实现方式,并遵循现代单例设计原则以优化性能和安全性。文中还提供了代码获取链接,便于读者实践与学习。
71 0
【高薪程序员必看】万字长文拆解Java并发编程!(9-2):并发工具-线程池
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的强力并发工具-线程池,废话不多说让我们直接开始。
150 0
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
248 83
Java虚拟线程:轻量级并发的革命性突破
Java虚拟线程:轻量级并发的革命性突破
186 83
说一说 Java 是如何实现线程间通信
我是小假 期待与你的下一次相遇 ~
说一说 JAVA 内存模型与线程
我是小假 期待与你的下一次相遇 ~
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问