线程组中的未受控的异常

可设置未捕获异常的处理类,处理在线程组中任一线程抛出的未捕获的异常。

任务

为一个线程组指定一个未捕获异常处理类,并生成多个可能抛出 ArithmeticException 异常的线程,捕获异常后中断线程组。

实现

本节的示例代码在 com.elanzone.books.noteeg.chpt1.sect12 package中

  • 自定义线程组 (MyThreadGroup)

    • 扩展 ThreadGroup
    public class MyThreadGroup extends ThreadGroup
    
    • 覆盖 uncaughtException 方法。
      此方法在线程组中任一线程抛出异常时被调用。 本例中此方法将抛出异常的线程信息和异常信息输出到控制台,并中断线程组中的其他异常。
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            System.out.printf("The thread %s has thrown an Exception\n",t.getId());
            e.printStackTrace(System.out);
            System.out.printf("Terminating the rest of the Threads\n");
            interrupt();
        }
    
  • 线程类 (Task)

    • run 方法
      本例中,我们将用1000除以一个随机数,这样当随机数生成器生成0时将产生一个除0的 ArithmeticException 异常。
            float result;
            Random random = new Random(Thread.currentThread().getId());
            while (true) {
                result = 1000 / ((int) (random.nextDouble() * 1000));
                System.out.printf("%d : %f\n", Thread.currentThread().getId(), result);
                if (Thread.currentThread().isInterrupted()) {
                    System.out.printf("%d : Interrupted\n", Thread.currentThread().getId());
                    return;
                }
            }
    
  • 控制类 (Main)

    • 创建一个 MyThreadGroup 和 Task 对象
        MyThreadGroup threadGroup = new MyThreadGroup("MyThreadGroup");
        Task task = new Task();
    
    • 创建多个线程对象,加入到线程组并启动
        for (int i = 0; i < 20; i++) {
            Thread thread = new Thread(threadGroup, task);
            thread.start();
        }
    

工作原理

当线程中抛出一个未捕获异常时,JVM按以下顺序查找处理此异常的 3 种可能的处理器:

  1. 线程的未捕获异常处理器
  2. 此线程所在线程组的未捕获异常处理器
  3. 缺省的未捕获异常处理器
  4. 将异常的 stack trace 输出到控制台并退出程序