zoukankan      html  css  js  c++  java
  • 关于java多线程中异常捕获的理解

    在java多线程程序中,所有线程都不允许抛出未捕获的checked exception(比如sleep时的InterruptedException)也就是说各个线程需要自己把自己的checked exception处理掉

    这句话怎么理解,最简单的看下图,也就是不能在Runnable的run方法上抛出异常,必须在里面捕获

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

    看下面的例子:

    public class ExceptionTest {
    
        public static void main(String[] args) {
            
            try {
                new Thread(new ExceptionTask()).start();
            } catch (Exception e) {
                System.out.println("注意看我是否能打印。。。");
                e.printStackTrace();
            }
        }
        
    }
    
    class ExceptionTask implements Runnable {
    
        @Override
        public void run() {
            System.out.println("".substring(0, 10));
        }
        
    }

    打印结果

    Exception in thread "Thread-0" java.lang.StringIndexOutOfBoundsException: String index out of range: 10
        at java.lang.String.substring(Unknown Source)
        at com.actuator.ExceptionTask.run(ExceptionTest.java:21)
        at java.lang.Thread.run(Unknown Source)

    从运行结果中,我们可以看到的是,"Thread-0"线程里的异常在main线程中没有catch到

    问题来了,我们如果需要捕获"Thread-0"线程的unchecked异常时该怎么办?Java SE5之后,我们可以通过Executor来解决这个问题。

    Thread.UncaughtExceptionHandler是java SE5中的新接口,它允许我们在每一个Thread对象上添加一个异常处理器。(UncaughtExceptionHandler)。Thread.UncaughtExceptionHandler.uncaughtException()方法会在线程因未捕获的异常而面临死亡时被调用

    下面这个例子简单的演示了如何使用UncaughtExceptionHandler。

    import java.lang.Thread.UncaughtExceptionHandler;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ThreadFactory;
    
    public class ExceptionTest {
    
        public static void main(String[] args) {
            
            // 下面有两种方式来执行线程
            
            // 第一种,非线程池写法
            Thread t = new Thread(new ExceptionTask());
            t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    System.out.println("线程"+t.getName()+"捕获到异常:"+e.getMessage());
                }
            });
            t.start();
            
            // 第二种,线程池写法
            ExecutorService executorService = Executors.newCachedThreadPool(new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    Thread t = new Thread(r);
                    t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
                        @Override
                        public void uncaughtException(Thread t, Throwable e) {
                            System.out.println("线程"+t.getName()+"捕获到异常:"+e.getMessage());
                        }
                    });
                    return t;
                }
            });
            executorService.execute(new ExceptionTask());
            
            
            
        }
        
    }
    
    class ExceptionTask implements Runnable {
    
        @Override
        public void run() {
            System.out.println("".substring(0, 10));
        }
        
    }

    两个执行结果一样

    线程Thread-0捕获到异常:String index out of range: 10
  • 相关阅读:
    pytest ini配置文件格式
    C#星辰之路
    bootstrap
    rabbitmq 安装
    curl 下载文件
    mysql 面试题
    mvn --version
    后台运行的nohup vs &
    scp
    linux下.tar.gz和.gz文件解压详解
  • 原文地址:https://www.cnblogs.com/shamo89/p/10340964.html
Copyright © 2011-2022 走看看