Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 24338|回复: 0

JAVA Thread线程异常监控

[复制链接]
  • TA的每日心情
    奋斗
    昨天 20:50
  • 签到天数: 786 天

    [LV.10]以坛为家III

    2049

    主题

    2107

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    722006
    发表于 2021-4-11 01:20:09 | 显示全部楼层 |阅读模式

     

    一、场景描述:单线程程序可以用try...catch捕获程序的异常,而在多线程程序的时候是无法使用try...catch捕获。

    示例1:多线程发生异常,无法使用try...catch捕获问题

    public class NoCaughtThread  implements Runnable{
        @Override
        public void run() {
            System.out.println(3 / 2);
            System.out.println(3 / 0);
            System.out.println(3 / 1);
        }
        
        public static void main(String[] args) {
            try {
                Thread thread = new Thread(new NoCaughtThread());
                thread.start();
            } catch (Exception e) {
                System.out.println("==Exception: " + e.getMessage());
            }
        }
    }

     运行结果:

    1
    Exception in thread "Thread-0" java.lang.ArithmeticException: / by zero
    at threadtest.NoCaughtThread.run(NoCaughtThread.java:7)
    at java.lang.Thread.run(Thread.java:724)

    显然这并非程序设定异常捕获,此时try...catch无法捕获线程的异常。此时,如果线程因为异常而终止执行将无法检测到异常。究其原因Thread类run()方法是不抛出任何检查型异常的,而自身却可能因为一个异常而被中止。

    二、解决方式大致有两种:① 在run()中设置对应的异常处理,主动方法来解决未检测异常;② Thread类API中提供Interface接口UncaughtExceptionHandler,该接口包含uncaughtException方法,它能检测出某个未捕获的异常而终结的情况;

    示例2:主动的检测异常

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class InitiativeCaught {
        public static void main(String[] args) {
            InitialtiveThread initialtiveThread = new InitialtiveThread() ;
            ExecutorService exec = Executors.newCachedThreadPool();
            exec.execute(initialtiveThread);
            exec.shutdown();
        }
    }
    
    class InitialtiveThread implements Runnable {
        @Override
        public void run() {
            Throwable thrown = null;
            try {
                System.out.println(3 / 2);
                System.out.println(3 / 0);
                System.out.println(3 / 1);
            } catch (Throwable e) {
                thrown = e;
            } finally {
                threadDeal(this, thrown);
            }
        }
        
        public void threadDeal(Runnable r, Throwable t) {
            System.out.println("==Exception: " + t.getMessage());
        }  
    }

     运行结果:

    1
    ==Exception: / by zero

    此时是主动捕获异常并做处理,得到想要的结果。

     

    示例3:Thread类API中提供UncaughtExceptionHandler接口捕获异常,要求检测线程异常,发生异常设置为重复调用三次之后结束线程。

    import java.lang.Thread.UncaughtExceptionHandler;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class ThreadMonitor implements Runnable {
        private int data;                    // 可设置通过构造传参
        private int control = 0;
        private static final int MAX = 3;    // 设置重试次数
        
        public ThreadMonitor(int i) {
            this.data = i;    
        }
        public ThreadMonitor() {
            // TODO Auto-generated constructor stub
        }
        
        @Override
        public void run() {
            Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread arg0, Throwable e) {
                    // TODO Auto-generated method stub
                    System.out.println("==Exception: " + e.getMessage());
                    String message = e.getMessage();
                    if( control==MAX ){
                        return ;
                    }else if( "ok".equals(message) ){
                        return ;
                    }else if ( "error".equals(message) ) {
                        new Thread() {
                            public void run() {
                                try {
                                    System.out.println("开始睡眠。");
                                    Thread.sleep(1 * 1000);
                                    control++ ;
                                    System.out.println("睡眠结束,control: "+ control);
                                    myTask(data) ;
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            };
                        }.start();
                    }else{
                        return ;
                    }
                }
            });  
            
            myTask(data) ;
            
        }
        
        @SuppressWarnings("finally")
        public void myTask(int data){
            boolean flag = true ;
            try {
                System.out.println(4 / data);
            } catch (Exception e) {
                flag = false ;
            } finally {
                if( flag ){
                    throw new RuntimeException("ok");
                }else{
                    throw new RuntimeException("error");
                }
            }
        }
        
        public static void main(String[] args) {
            ExecutorService exec = Executors.newCachedThreadPool();
            ThreadMonitor threadMonitor = new ThreadMonitor(0);
            exec.execute(threadMonitor);
            exec.shutdown();
        }
    }

     运行结果:

    ==Exception: error
    开始睡眠。
    睡眠结束,control: 1
    ==Exception: error
    开始睡眠。
    睡眠结束,control: 2
    ==Exception: error
    开始睡眠。
    睡眠结束,control: 3
    ==Exception: error

     

    此时,可以正常捕获线程因除数为零造成的中断。其中:

    (1) 在Thread类API中提供Interface接口UncaughtExceptionHandler,该接口包含一个uncaughtException方法,它能检测出某个由于未捕获的异常而终结的情况。定义如下:

    UncaughtExceptionHandler接口:  public static interface Thread.UncaughtExceptionHandler

    uncaughtException方法: public void uncaughtException(Thread t, Throwable e)

    (2) uncaughtException方法会捕获线程的异常,此时需要覆写该方法设定自定义的处理方式。

    (3) 设置UncaughtExceptionHandler异常处理:

    方式一:通过Thread提供的静态static方法,设置默认异常处理:public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler ux)

    方式二:通过方法:public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

    (4) UncaughtExceptionHandler异常处理需要设置在run()方法内,否则无法捕获到线程的异常。

    (5) 参考链接:

    JAVA下内存池启动程序:http://www.cnblogs.com/zhujiabin/p/5404771.html

    JAVA下多线程异常处理:http://blog.csdn.net/u013256816/article/details/50417822 

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-8-28 17:24 , Processed in 0.062919 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表