首页 > 其他分享 >主线程如何获取子线程异常

主线程如何获取子线程异常

时间:2023-11-29 19:58:25浏览次数:29  
标签:Thread 主线 System 获取 线程 println new out

主线程如何获取子线程异常

  • 常规情况:
    一般我们没有办法通过主线程去获取子线程的异常
    举个例子:
    public class test11_29{
        public static void main(String[] args) {
            try {
                Thread thread = new Thread(new myExceptionRunner());
                thread.start();
            } catch (Exception e) {
                //无法捕获子线程的异常
                System.out.println(""there is error! "");
                e.printStackTrace();
            }
            System.out.println("this is main");
        }
    }
    class myExceptionRunner implements Runnable{
    
        @Override
        public void run() {
            System.out.println("other thread is running");
            System.out.println("------------------");
            throw new RuntimeException("this is error!");
        }
    }
    
    结果如下:
    this is main
    running
    ------------------
    Exception in thread "Thread-0" java.lang.RuntimeException: this is error!
        at review.myExceptionRunner.run(test11_29.java:23)
        at java.base/java.lang.Thread.run(Thread.java:842)
    
    通过结果可以发现,子线程抛出错误,我们却无法进入到catch中的代码块,因此可以证明主线程是无法区获取子线程相关错误的
    因此,我们只能自己去实现获取子线程的错误
    对此,我们有两种方法:

第一种:通过自定义工厂方法实现

设置每一个线程执行时候的异常处理
1.自定义工厂方法

   class HandlerThreadFactory implements ThreadFactory{

       @Override
       public Thread newThread(Runnable r) {
           System.out.println("create thread t");
           Thread thread = new Thread(r);
           System.out.println("set uncaughtException for t");
           //将自定义好的拦截方法设置进去
           thread.setUncaughtExceptionHandler(new MyUncaughExceptionHandler());
           return thread;
       }
   }

2.自定义错误拦截方法

    class MyUncaughExceptionHandler implements Thread.UncaughtExceptionHandler{

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

3.捕捉自线程错误实现

    public class test11_29 {
        public static void main(String[] args) {
            System.out.println("this is main");
            //必须我们自己实现
            System.out.println("第一种");
            //通过自定义工厂方法实现
            //自定义工厂方法作为创建线程池的参数
            ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(new HandlerThreadFactory());
            //执行相关线程方法
            newCachedThreadPool.execute(new myExceptionRunner());
            newCachedThreadPool.shutdown();
        }
    }

4.汇总在一起,代码如下

    public class test11_29 {
        public static void main(String[] args) {
            System.out.println("this is main");
            //必须我们自己实现
            System.out.println("第一种");
            //通过自定义工厂方法实现
             //自定义工厂方法作为创建线程池的参数
            ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(new HandlerThreadFactory());
            //执行相关线程方法
            newCachedThreadPool.execute(new myExceptionRunner());
            newCachedThreadPool.shutdown();
        }
    }
    class myExceptionRunner implements Runnable{
        @Override
        public void run() {
            System.out.println("other thread is running");
            System.out.println("------------------");
            throw new RuntimeException("this is error!");
        }
    }
    class MyUncaughExceptionHandler implements Thread.UncaughtExceptionHandler{

        @Override
        public void uncaughtException(Thread t, Throwable e) {
            System.out.println("caught:" + e);
        }
    }
    class HandlerThreadFactory implements ThreadFactory{

        @Override
        public Thread newThread(Runnable r) {
            System.out.println("create thread t");
            Thread thread = new Thread(r);
            System.out.println("set uncaughtException for t");
            //将自定义好的拦截方法设置进去
            thread.setUncaughtExceptionHandler(new MyUncaughExceptionHandler());
            return thread;
        }
    }

结果如下:

this is main
第一种
create thread t
set uncaughtException for t
other thread is running
------------------
caught:java.lang.RuntimeException: this is error!

第二种:通过默认方法,不去自定义工厂方法

每一个线程的异常处理相同,使用Thread的静态方法
1.自定义错误拦截方法

class MyUncaughExceptionHandler implements Thread.UncaughtExceptionHandler{

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

2.实现子线程错误捕捉

public class test11_29 {
    public static void main(String[] args) {
        
        System.out.println("this is main");
        // //必须我们自己实现
        System.out.println("第二种");
        //通过默认方法进行实现
        //直接设置错误拦截器
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughExceptionHandler());
        //默认方法创建线程池
        ExecutorService newCachedThreadPool2 = Executors.newCachedThreadPool();
        //启动子线程
        newCachedThreadPool2.execute(new myExceptionRunner());
        newCachedThreadPool2.shutdown();
    }
    
}

3.汇总代码如下

public class test11_29 {
        public static void main(String[] args) {
            System.out.println("this is main");
        // //必须我们自己实现
        System.out.println("第二种");
        //通过默认方法进行实现
        //直接设置错误拦截器
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughExceptionHandler());
        //默认方法创建线程池
        ExecutorService newCachedThreadPool2 = Executors.newCachedThreadPool();
        //启动子线程
        newCachedThreadPool2.execute(new myExceptionRunner());
        newCachedThreadPool2.shutdown();
        }
    }
    class myExceptionRunner implements Runnable{
        @Override
        public void run() {
            System.out.println("other thread is running");
            System.out.println("------------------");
            throw new RuntimeException("this is error!");
        }
    }
    class MyUncaughExceptionHandler implements Thread.UncaughtExceptionHandler{

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

运行结果如下

this is main
第二种
other thread is running
------------------
caught:java.lang.RuntimeException: this is error!

总结

主线程无法获取子线程的错误,因此我们需要自定义去实现相关子线程的错误拦截方法
第一种:
设置工厂方法,将拦截方法在工厂方法创建线程时设置进去
第二种:
在主线程中直接利用Thread.setDefaultUncaughtExceptionHandler(new MyUncaughExceptionHandler());设置错误拦截方法

共同点是都会使用 Thread.setDefaultUncaughtExceptionHandler(new MyUncaughExceptionHandler()); 方法去设置错误拦截方法,只不过是创建方式不同,应用场景不同。

比之上述方法,还有一种编程上的处理方式可以借鉴,即,有时候主线程的调用方可能只是想知道子线程执行过程中发生过哪些异常,而不一定会处理或是立即处理,那么发起子线程的方法可以把子线程抛出的异常实例收集起来作为一个Exception的List返回给调用方,由调用方来根据异常情况决定如何应对。不过要特别注意的是,此时子线程早以终结。

线程设计的理念:“线程的问题应该线程自己本身来解决,而不要委托到外部。”

参考来源:
Java中主线程如何捕获子线程抛出的异常
java主线程捕获子线程中的异常

标签:Thread,主线,System,获取,线程,println,new,out
From: https://www.cnblogs.com/kckte66/p/17865694.html

相关文章

  • Ant-Design modal对话框未打开时,无法通过uesRef获取modal内部元素DOM节点
    为什么要记录下来呢?因为我在网上和chatGpt上没有搜到合适的解决方案。在CDNS上看到个和我遇到问题一样的,居然要收费才能看,所以自己记下来。当然肯定还有其他的好方案,欢迎大家留言。需求:使用antdV/g6画关系图,类似于企查查上面的那样:点击按钮打开Modal框,把数据渲染到Modal框的div......
  • Android 两种方获取U盘的挂载路径
    第一种publicStringgetUsbPath(){try{StorageManagersm=(StorageManager)MyApplication.getContext().getSystemService(STORAGE_SERVICE);MethodgetVolumePathsMethod=StorageManager.class.getMethod("getVolumePaths&qu......
  • 获取Windows内核对象的索引与对象名
    下列提出两种获取对象名的方式通过_OBJECT_TYPE::Name获取对象名称,通过_OBJECT_TYPE::Index获取对象索引;通过NtQueryObject的方式获取,r0与r3通用,代码如下:#include<cstdio>#include<cstdlib>#include<iostream>#include<Windows.h>#defineNT_SUCCESS(Status)((NTST......
  • 获取今天零点的时间戳
    #获取今天零点的时间戳#获取当前时间戳,取余一天的秒数86400,得到今天过了多少秒#用当前的时间戳减去今天过去的秒数,得到今天零点的时间戳#注意要减去time.timezone获取当前时区的时间戳importtimefromdatetimeimportdatetimenow_time=int(time.time())day_time......
  • .Net Core 单元测试获取配置文件节点值
     单元测试类:ServiceProvider_serviceProvider;IConfiguration_config;[SetUp]publicvoidSetup(){_config=newConfigurationBuilder().Add(newJsonConfigurationSource{Path="appsettings.jso......
  • js和python获取1-100之间的质数
    jsfor(leti=2;i<=100;i++){letiszs=truefor(letj=2;j<i;j++){if(i%j===0){iszs=falsebreak}}if(iszs){zs.push(i)}}console.log(zs)pythonzs=[]foriinrange(2,101):iszs......
  • windows 获取 序列号 wwid方法
     以下任意一条命令都可以:wmicdiskdrivegetserialnumberwmicpathwin32_physicalmediagetSerialNumberwmicpathWin32_DiskDrivegetSerialNumber运行结果: **注意**:windows7下获取的序列号格式可能和Windows10下的不一样获取硬盘的更多信息wmicdis......
  • 使用axios获取接口返回二进制流进行文件下载
    1、当接口返回值类型是'application/json'时,处理报错信息1if(response.data.type&&response.data.type=='application/json'){2letreader=newFileReader();3//处理load事件。该事件在读取操作完成时触发4reader.onload=e=>......
  • c# HtmlAgilityPack获取笔趣阁小说
        publicpartialclassForm2:Form{publicForm2(){InitializeComponent();}privatevoidForm2_Load(objectsender,EventArgse){}publicclassResult{///<summary>......
  • 发烧平台完全是AMD的天下!32核心线程撕裂者者7970X评测:内容创作性价比之选
    一、前言:32核心的线程撕裂者7970X11月20日,AMD正式发布了Zen4架构的线程撕裂者处理器,成为了无可争议的最强处理器,我们快科技也同步带来了HEDT发烧平台旗舰型号,64核心128线程线程撕裂者7980X的首发评测。除了线程撕裂者7980X之外,AMD同时还发布了32核心的线程撕裂者7970X、24核心......