zoukankan      html  css  js  c++  java
  • JAVA基础知识之多线程——线程组和未处理异常

    线程组

    Java中的ThreadGroup类表示线程组,在创建新线程时,可以通过构造函数Thread(group...)来指定线程组。

    线程组具有以下特征

    如果没有显式指定线程组,则新线程属于默认线程组,默认情况下,与创建线程所在的组相同

    一旦确定了线程所在线程组之后,不允许更改线程组,直到线程死亡

    对于线程组ThreadGroup的一个对象,就表示一个线程组,线程组通过ThreadGroup(group...)来初始化,

    线程组可以通过interrput(), setDamemon(),setMaxPriority()等方法来操作组内线程,通过activeCount(),isDamemon()来获取线程信息

    下面是一个例子,

     1 package threads;
     2 
     3 public class MyThread extends Thread {
     4     public MyThread(String name) {
     5         super(name);
     6     }
     7     
     8     public MyThread(ThreadGroup group, String name) {
     9         super(group,name);
    10     }
    11     
    12     public void run() {
    13         for (int i = 0; i<10; i++) {
    14             System.out.println(getName() + " 线程的i变量 " + i);
    15         }
    16     }
    17 }
     1 package threads;
     2 
     3 public class ThreadGroupTest {
     4     public static void main(String[] args) {
     5         //获取主线程所在的线程组,这是所有线程默认的线程组
     6         ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
     7         System.out.println("主线程组的名字: "+mainGroup.getName());
     8         System.out.println("主线程组是否为后台线程组: "+ mainGroup.isDaemon());
     9         new MyThread("主线程组的线程").start();
    10         ThreadGroup tg = new ThreadGroup("新线程组");
    11         tg.setDaemon(true);
    12         MyThread tt = new MyThread(tg, "tg线程组的线程甲");
    13         tt.start();
    14         new Thread(tg,"tg线程组的线程乙").start();
    15     }
    16 }

     未处理异常

    JAVA5之后,JVM会在线程抛出未处理异常后自动查找是否有对应的“未处理异常”处理对象,即Thread.UncaughtExceptionHandler对象,如果找到了该处理器对象,就会调用对象的uncaughtException来处理异常。

    Thread提供了两个方法来自定义(未处理的)异常处理,

    setDefaultUncaughtExceptionHandler(eh), 为线程类的所有实例设置默认的异常处理器

    setUncaughtExceptionHandler(eh),为指定线程实例设置异常处理器

    而在线程组中,因为ThreadGroup类也实现了Thread.UncaughtExceptionHandler接口,所以线程组会成为默认的异常处理器。

    线程组处理异常的流程如下,

    • 如果该线程组有父线程组,则调用父线程组的uncaughtException方法来处理异常
    • 如果线程类有默认异常处理器,则用该异常处理器处理异常
    • 如果异常对象不是ThreadDeath,就会打印异常信息,并结束该线程

    下面演示一个例子,为主线程设置一个默认的异常处理器,当主程序抛出一个未处理异常时,该异常处理器将会起作用。

    当一个线程抛出一个未处理异常时,JVM首先会查找该异常对应的异常处理器,

     1 package threads;
     2 
     3 //自定义异常处理器,只需要实现Thread.UncaughtExceptionHandler接口
     4 public class MyExHandler implements Thread.UncaughtExceptionHandler {
     5 
     6     //uncaughtException方法将处理线程中未处理的异常
     7     @Override
     8     public void uncaughtException(Thread t, Throwable e) {
     9         // TODO Auto-generated method stub
    10         System.out.println("自定义异常处理: "+ t + " 线程出现了异常 " + e);
    11     }
    12 }
     1 package threads;
     2 
     3 public class ExHandler {
     4     public static void main(String[] args) {
     5         //设置主线程的默认异常处理器
     6         Thread.currentThread().setUncaughtExceptionHandler(new MyExHandler());
     7         int a = 5/0;
     8         System.out.println("程序正常结束");
     9     }
    10 }

    执行结果,可以看到程序虽然用自定义的异常处理器处理了一个未处理的异常,但还是没有正常结束程序,而是在处理完异常后直接结束了程序。

    1 自定义异常处理: Thread[main,5,main] 线程出现了异常 java.lang.ArithmeticException: divide by zero

    如果注释掉主程序中的第6行,让JVM来处理未处理的异常,执行结果如下,也是不能正常结束程序

    1 Exception in thread "main" java.lang.ArithmeticException: divide by zero
    2     at threads.ExHandler.main(ExHandler.java:7)

    如果使用try catch finally来处理, 修改主程序如下,

     1 package threads;
     2 
     3 public class ExHandler {
     4     public static void main(String[] args) {
     5         //设置主线程的默认异常处理器
     6         //Thread.currentThread().setUncaughtExceptionHandler(new MyExHandler());
     7         try {
     8             int a = 5/0;
     9         } catch (ArithmeticException e) {
    10             e.printStackTrace();
    11         } finally {
    12             System.out.println("程序正常结束");
    13         }
    14     }
    15 }

    执行结果如下,可以看到这时候程序可以正常结束了,说明用try catch处理异常时,异常不会向上传给调用者

    1 java.lang.ArithmeticException: divide by zero程序正常结束
    2 
    3     at threads.ExHandler.main(ExHandler.java:8)

    以下引用自 阿里巴巴Java开发手册

    9. 【强制】多线程并行处理定时任务时,Timer运行多个TimeTask 时,只要其中之一没有捕获

    抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。

  • 相关阅读:
    【芯片】国产MCU替代ST芯片调查
    【生产线】包装如何防止配件漏装
    【标准】运输振动试验
    【bat】批量提取文件夹内文件的名称
    【VBA】从批量excel文件中获取数据
    【滤波器】抗混叠滤波器
    【元器件】晶振TCXO、OCXO
    【C】三点求抛物线顶点
    德卡T10读卡器 读取身份证号码和身份证UID
    C# 执行查询语句,返回DataSet
  • 原文地址:https://www.cnblogs.com/fysola/p/6074862.html
Copyright © 2011-2022 走看看