如何捕获java线程中的逃逸的异常

简介: 在java线程中,在run方法中,我们要在run()方法中,把一切的异常有处理掉,也就try-catch掉。不能让这个线程抛出异常,因为如果我们不使用特殊的方式的话,我们是无法捕获从这个线程中逃逸的异常的。异常一旦抛出了,那么这个线程就会停止运行,但是不会影响主线程和其它的线程。因为主线程和其它的线程都不知道它抛出了异常。线程在run方法抛出异常,没有catch

在java线程中,在run方法中,我们要在run()方法中,把一切的异常有处理掉,也就try-catch掉。不能让这个线程抛出异常,因为如果我们不使用特殊的方式的话,我们是无法捕获从这个线程中逃逸的异常的。异常一旦抛出了,那么这个线程就会停止运行,但是不会影响主线程和其它的线程。因为主线程和其它的线程都不知道它抛出了异常。

线程在run方法抛出异常,没有catch

这里写图片描述

那么会有疑问,是不是在main函数里面没有catch

```
package Thread.UncaughtExceptionHandler;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 测试线程抛异常不能捕获
 * @author yxx
 */
public class ExceptionThread implements Runnable {

    @Override
    public void run() {
        System.out.println("我准备抛出异常,你能接到吗?");
        throw new RuntimeException();
    }
    public static void main(String[] args) {
        try {
            Thread thread = new Thread(new ExceptionThread());
            ExecutorService exec = Executors.newCachedThreadPool();
            exec.execute(thread);
        } catch (Exception e) {
            System.out.println("我要捉住异常");
            e.printStackTrace();
        }
    }
}

这里写图片描述

一样是catch不到的,想想一个线程的抛出异常之后就终止了如果再进行catch,都不在一个线程里面

所以这个时候我们得去实现UncaughtExceptionHandler这个接口来捕获抛出的异常

实现UncaughtExceptionHandler这个接口来捕获抛出的异常

ExceptionThread2.java

package Thread.UncaughtExceptionHandler;

/**
 * 一个抛出异常的线程类 但是想被抓住
 * @author yxx
 */
public class ExceptionThread2 implements Runnable {

    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("run by " + t.getName());
        System.out.println("Exception " + t.getUncaughtExceptionHandler());
        throw new RuntimeException();
    }
}

ExceptionThread3.java

package Thread.UncaughtExceptionHandler;

/**
 * 一个抛出异常的线程类 但是想被抓住
 * @author yxx
 */
public class ExceptionThread3 implements Runnable {

    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("run by " + t.getName());
        System.out.println("Exception " + t.getUncaughtExceptionHandler());
        throw new NullPointerException();
    }

}

MyUncaughtExceptionHandler.java

package Thread.UncaughtExceptionHandler;

import java.lang.Thread.UncaughtExceptionHandler;

/**
 * 实现UncaughtExceptionHandler接口,抓住抛出的异常
 * @author yxx
 *
 */
public class MyUncaughtExceptionHandler implements UncaughtExceptionHandler {

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("caugth: " + e.toString());
    }
}

HandlerThreadFactory.java

package Thread.UncaughtExceptionHandler;

import java.util.concurrent.ThreadFactory;

/**
 * 实现ThreadFactory来创建线程,为每一个thread对象都附上一个未捕获异常的处理器
 * @author yxx
 *
 */
public class HandlerThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {
        System.out.println(this + "creating new thread");
        Thread t = new Thread(r);
        System.out.println("created" + t);
        //为每一个线程设置异常捕获器
        t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        System.out.println("eh = " + t.getUncaughtExceptionHandler());
        return t;
    }
}

CaptureUncaughtException.java

package Thread.UncaughtExceptionHandler;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 准备创建线程抛出异常,线程外捕获
 * @author yxx
 *
 */
public class CaptureUncaughtException {

    public static void main(String[] args) {
        ExecutorService es = Executors.newCachedThreadPool(new HandlerThreadFactory());
        es.execute(new ExceptionThread2());
        es.execute(new ExceptionThread3());
    }
}

运行截图

这里写图片描述

都能捕获到

如果你知道将要在代码中处处使用相同的异常处理器,那么更加简单的方式是在Thread类中设置一个静态域,并将这个处理器设置为默认的未捕获异常的处理器。

在Thread类中设置一个静态域

SettingDefaultHandler.java

package Thread.UncaughtExceptionHandler;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 如果你知道将要在代码中处处使用相同的异常处理器,那么更加简单的方式是在Thread类中设置一个静态域,
 * 并将这个处理器设置为默认的未捕获异常的处理器。
 * @author yxx
 *
 */
public class SettingDefaultHandler {
    public static void main(String[] args) {
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());

        ExecutorService es = Executors.newCachedThreadPool();
        es.execute(new ExceptionThread2());
    }
}

静态域执行效果图

这里写图片描述

说明:这个处理器只有在不存在线程专有的未捕获异常的情况下才会被调用。系统会检查线程的专有的版本,如果没有发现,则检查线程组是有有其专有的uncaughtException()方法。如果也没有,在调用defaultUncaughtExcept。

在java多线程程序中,所有线程都不允许抛出未捕获的checked exception(比如sleep时的InterruptedException),也就是说各个线程需要自己把自己的checked exception处理掉。这一点是通过java.lang.Runnable.run()方法声明(因为此方法声明上没有throw exception部分)进行了约束。但是线程依然有可能抛出unchecked exception(如运行时异常),当此类异常跑抛出时,线程就会终结,而对于主线程和其他线程完全不受影响,且完全感知不到某个线程抛出的异常(也是说完全无法catch到这个异常)。JVM的这种设计源自于这样一种理念:线程是独立执行的代码片断,线程的问题应该由线程自己来解决,而不要委托到外部。”“基于这样的设计理念,在Java中,线程方法的异常(无论是checked还是unchecked exception),都应该在线程代码边界之内(run方法内)进行try catch并处理掉.换句话说,我们不能捕获从线程中逃逸的异常。

目录
相关文章
|
3天前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
3天前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
4天前
|
消息中间件 前端开发 NoSQL
面试官:线程池遇到未处理的异常会崩溃吗?
面试官:线程池遇到未处理的异常会崩溃吗?
30 3
面试官:线程池遇到未处理的异常会崩溃吗?
|
7天前
|
Java 调度 开发者
Java并发编程:深入理解线程池
在Java的世界中,线程池是提升应用性能、实现高效并发处理的关键工具。本文将深入浅出地介绍线程池的核心概念、工作原理以及如何在实际应用中有效利用线程池来优化资源管理和任务调度。通过本文的学习,读者能够掌握线程池的基本使用技巧,并理解其背后的设计哲学。
|
6天前
|
缓存 监控 Java
Java中的并发编程:理解并应用线程池
在Java的并发编程中,线程池是提高应用程序性能的关键工具。本文将深入探讨如何有效利用线程池来管理资源、提升效率和简化代码结构。我们将从基础概念出发,逐步介绍线程池的配置、使用场景以及最佳实践,帮助开发者更好地掌握并发编程的核心技巧。
|
3天前
|
Java 调度 开发者
Java中的多线程基础及其应用
【9月更文挑战第13天】本文将深入探讨Java中的多线程概念,从基本理论到实际应用,带你一步步了解如何有效使用多线程来提升程序的性能。我们将通过实际代码示例,展示如何在Java中创建和管理线程,以及如何利用线程池优化资源管理。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧,帮助你更好地理解和应用多线程编程。
|
8天前
|
缓存 监控 Java
java中线程池的使用
java中线程池的使用
|
8天前
|
算法 Java 数据处理
Java并发编程:解锁多线程的力量
在Java的世界里,掌握并发编程是提升应用性能和响应能力的关键。本文将深入浅出地探讨如何利用Java的多线程特性来优化程序执行效率,从基础的线程创建到高级的并发工具类使用,带领读者一步步解锁Java并发编程的奥秘。你将学习到如何避免常见的并发陷阱,并实际应用这些知识来解决现实世界的问题。让我们一起开启高效编码的旅程吧!
|
10天前
|
Java 开发者
Java中的多线程编程基础与实战
【9月更文挑战第6天】本文将通过深入浅出的方式,带领读者了解并掌握Java中的多线程编程。我们将从基础概念出发,逐步深入到代码实践,最后探讨多线程在实际应用中的优势和注意事项。无论你是初学者还是有一定经验的开发者,这篇文章都能让你对Java多线程有更全面的认识。
15 1
|
7天前
|
安全 Java UED
Java并发编程:解锁多线程的潜力
在Java的世界里,并发编程如同一场精心编排的交响乐,每个线程扮演着不同的乐手,共同奏响性能与效率的和声。本文将引导你走进Java并发编程的大门,探索如何在多核处理器上优雅地舞动多线程,从而提升应用的性能和响应性。我们将从基础概念出发,逐步深入到高级技巧,让你的代码在并行处理的海洋中乘风破浪。