【线程】ThreadGroup 实战与剖析 (十七)

我的原则:先会用再说,内部慢慢来。
学以致用,根据场景学源码


一、前言

1.1 架构

在这里插入图片描述

在这里插入图片描述
=== 点击查看top目录 ===

1.2 ThreadGroup 能干嘛?

  1. 能用来操作group下面的所有线程,比如全部打断 interrupt
  2. 可以进行链路监控,例如监控某个 group 下面,当前存在多少活跃线程数目。
  3. 统一捕获该group下线程抛出的异常。

1.3 ThreadGroup 常用的方法

方法 描述
int activeCount() 查看组内部 thread 活跃数量(包括子group)
int activeGroupCount() 查看组内部 group 活跃数量(包括子group)
void list() 打印出group下的所有线程信息(包括子group)
void destroy() 摧毁线程(包括子group)
boolean isDestroyed() 查看该 group 有没有被摧毁
int enumerate(Thread[] list) copy 某个group 下面的活跃 thread
ThreadGroup getParent() 找爸爸
void interrupt() 打断这个 group 下面的所有 thread
boolean isDaemon() 看下是否是幽灵线程
void setDaemon(boolean daemon) 设置幽灵线程

二、实战

2.1 实战一 :验证 Count

  • 本demo验证了activeCount、activeGroupCount、list、getParent、interrupt 等一系列方法
  • 代码流程如下:
  1. 创建 group1
  2. group1 先创建thread1,2,3 ,由于没start,activeCount得到的的结果是 0
  3. thread1,2,3 启动起来(暂时不关闭),activeCount得到的的结果是 3
  4. 插入 thread4, 启动起来,activeCount得到的的结果是 4
  5. thread4 线程跑完,activeCount得到的的结果是 3
  6. 创建group2(传入 group1)
  7. 打印出 group2,group1,还有顶级 main 的list信息
  8. interrupt 测试打断,诶,虽然main线程跑到最后了,打那是发现scanner.nextLine() 由于内部的死循环while,无法被打断。
public static void testGroupListAndSize() throws Exception {
        ThreadGroup group1 = new ThreadGroup("Group1");

        Thread t1 = new Thread(group1, () -> {
            try {
                Scanner sc = new Scanner(System.in);
                System.out.println("点击任意键唤醒线程 ...");
                sc.nextLine();
            } catch (Exception e) {
                System.out.println("t1 被打断啦 ...");
            }
        });
        Thread t2 = new Thread(group1, () -> {
            try {
                Scanner sc = new Scanner(System.in);
                System.out.println("点击任意键唤醒线程 ...");
                sc.nextLine();
            } catch (Exception e) {
                System.out.println("t2 被打断啦 ...");
            }

        });
        Thread t3 = new Thread(group1, () -> {
            try {
                Scanner sc = new Scanner(System.in);
                System.out.println("点击任意键唤醒线程 ...");
                sc.nextLine();
            } catch (Exception e) {
                System.out.println("t3 被打断啦 ...");
            }
        });
        /*
            1. 线程未启动,未注册到 group 里面去
         */
        group1.list();
        System.out.println("group1.size ->  " + group1.activeCount());

        Thread.sleep(1000);
        System.out.println("----");

        /*
            2. 启动线程
         */
        t1.start();
        t2.start();
        t3.start();
        Thread.sleep(1000);
        group1.list();
        System.out.println("group1.size ->  " + group1.activeCount());
        System.out.println("----");
        System.out.println("==== 启动 thread4,验证 activeCount 含义(只返回活跃数量) ====");

        /*
            启动 thread4,验证 activeCount 含义(只返回活跃数量)
         */
        Thread t4 = new Thread(group1, () -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("t4 被打断啦 ...");
            }
        });
        t4.start();
        group1.list();
        System.out.println("group1.size ->  " + group1.activeCount());
        System.out.println("----");
        Thread.sleep(2000);
        System.out.println(" === 2s 后 ,t4 已经down ===");
        group1.list();
        System.out.println("group1.size ->  " + group1.activeCount());
        System.out.println("----");

        Thread.sleep(1000);
        System.out.println("==== 创建子group ====");
        ThreadGroup group2 = new ThreadGroup(group1,"Group2");
        Thread t21 = new Thread(group2, () -> {
            try {
                Scanner sc = new Scanner(System.in);
                System.out.println("点击任意键唤醒线程 ...");
                sc.nextLine();
            } catch (Exception e) {
                System.out.println("t21 被打断啦 ...");
            }
        });
        t21.start();
        Thread.sleep(1000);
        System.out.println("遍历下 group1 ,观察是否加入了...");
        group1.list();
        System.out.println("遍历下 group2 ...");
        group2.list();
        System.out.println("最后遍历下最牛逼的 group-main ...");
        Thread.currentThread().getThreadGroup().list();

        Thread.sleep(1000);
        /*
            interrupt
         */
        System.out.println("=== 最后打断全部线程 ===");
//        group1.destroy();
        group1.interrupt();
        /*
            sc.nextLine(); 太牛逼了,里面有死循环,听不到外面的打断
         */
        System.out.println("main thread end ...");
    }
  • 输出:
java.lang.ThreadGroup[name=Group1,maxpri=10]
group1.size ->  0
----
点击任意键唤醒线程 ...
点击任意键唤醒线程 ...
点击任意键唤醒线程 ...
java.lang.ThreadGroup[name=Group1,maxpri=10]
    Thread[Thread-0,5,Group1]
    Thread[Thread-1,5,Group1]
    Thread[Thread-2,5,Group1]
group1.size ->  3
----
==== 启动 thread4,验证 activeCount 含义(只返回活跃数量) ====
java.lang.ThreadGroup[name=Group1,maxpri=10]
    Thread[Thread-0,5,Group1]
    Thread[Thread-1,5,Group1]
    Thread[Thread-2,5,Group1]
    Thread[Thread-3,5,Group1]
group1.size ->  4
----
 === 2s 后 ,t4 已经down ===
java.lang.ThreadGroup[name=Group1,maxpri=10]
    Thread[Thread-0,5,Group1]
    Thread[Thread-1,5,Group1]
    Thread[Thread-2,5,Group1]
group1.size ->  3
----
==== 创建子group ====
点击任意键唤醒线程 ...
遍历下 group1 ,观察是否加入了...
java.lang.ThreadGroup[name=Group1,maxpri=10]
    Thread[Thread-0,5,Group1]
    Thread[Thread-1,5,Group1]
    Thread[Thread-2,5,Group1]
    java.lang.ThreadGroup[name=Group2,maxpri=10]
        Thread[Thread-4,5,Group2]
遍历下 group2 ...
java.lang.ThreadGroup[name=Group2,maxpri=10]
    Thread[Thread-4,5,Group2]
最后遍历下最牛逼的 group-main ...
java.lang.ThreadGroup[name=main,maxpri=10]
    Thread[main,5,main]
    Thread[Monitor Ctrl-Break,5,main]
    java.lang.ThreadGroup[name=Group1,maxpri=10]
        Thread[Thread-0,5,Group1]
        Thread[Thread-1,5,Group1]
        Thread[Thread-2,5,Group1]
        java.lang.ThreadGroup[name=Group2,maxpri=10]
            Thread[Thread-4,5,Group2]
=== 最后打断全部线程 ===
main thread end ...

...
注意,这个地方子线程没有中断!!!一直跑着!!!

=== 点击查看top目录 ===

2.2 实战二 :验证 Interrupt

  • 注意,上面这个程序,子线程没有中断!!!一直跑着!!!
  • 由于上面有bug,我们重新验证下 interrupt 方法
Thread t1 = new Thread(group1, () -> {
     try {
         Thread.sleep(10000);
     } catch (Exception e) {
         System.out.println("t1 被打断啦 ...");
     }
 });
  • 改动一下线程的内部实现,其余地方简化一下
public static void testInterrupte() throws Exception {
        ThreadGroup group1 = new ThreadGroup("Group1");

        Thread t1 = new Thread(group1, () -> {
            try {
                Thread.sleep(10000);
            } catch (Exception e) {
                System.out.println("t1 被打断啦 ...");
            }
        });
        Thread t2 = new Thread(group1, () -> {
            try {
                Thread.sleep(10000);
            } catch (Exception e) {
                System.out.println("t2 被打断啦 ...");
            }

        });
        Thread t3 = new Thread(group1, () -> {
            try {
                Thread.sleep(10000);
            } catch (Exception e) {
                System.out.println("t3 被打断啦 ...");
            }
        });

        /*
            2. 启动线程
         */
        t1.start();
        t2.start();
        t3.start();
        Thread.sleep(1000);
        group1.list();
        System.out.println("group1.size ->  " + group1.activeCount());
        System.out.println("----");
        System.out.println("==== 启动 thread4,验证 activeCount 含义(只返回活跃数量) ====");

        Thread.sleep(1000);
        System.out.println("==== 创建子group ====");
        ThreadGroup group2 = new ThreadGroup(group1,"Group2");
        Thread t21 = new Thread(group2, () -> {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                System.out.println("t21 被打断啦 ...");
            }
        });
        t21.start();
        Thread.sleep(1000);
        System.out.println("遍历下 group1 ,观察是否加入了...");
        group1.list();
        System.out.println("遍历下 group2 ...");
        group2.list();
        System.out.println("最后遍历下最牛逼的 group-main ...");
        Thread.currentThread().getThreadGroup().list();

        Thread.sleep(1000);
        /*
            interrupt
         */
        System.out.println("=== 最后打断全部线程 ===");
//        group1.destroy();
        group1.interrupt();

        System.out.println("main thread end ...");
    }

输出:

java.lang.ThreadGroup[name=Group1,maxpri=10]
    Thread[Thread-0,5,Group1]
    Thread[Thread-1,5,Group1]
    Thread[Thread-2,5,Group1]
group1.size ->  3
----
==== 启动 thread4,验证 activeCount 含义(只返回活跃数量) ====
==== 创建子group ====
遍历下 group1 ,观察是否加入了...
java.lang.ThreadGroup[name=Group1,maxpri=10]
    Thread[Thread-0,5,Group1]
    Thread[Thread-1,5,Group1]
    Thread[Thread-2,5,Group1]
    java.lang.ThreadGroup[name=Group2,maxpri=10]
        Thread[Thread-3,5,Group2]
遍历下 group2 ...
java.lang.ThreadGroup[name=Group2,maxpri=10]
    Thread[Thread-3,5,Group2]
最后遍历下最牛逼的 group-main ...
java.lang.ThreadGroup[name=main,maxpri=10]
    Thread[main,5,main]
    Thread[Monitor Ctrl-Break,5,main]
    java.lang.ThreadGroup[name=Group1,maxpri=10]
        Thread[Thread-0,5,Group1]
        Thread[Thread-1,5,Group1]
        Thread[Thread-2,5,Group1]
        java.lang.ThreadGroup[name=Group2,maxpri=10]
            Thread[Thread-3,5,Group2]
=== 最后打断全部线程 ===
main thread end ...
t1 被打断啦 ...
t2 被打断啦 ...
t3 被打断啦 ...

JVM跑完全程,无任何地方卡住。

=== 点击查看top目录 ===

2.3 实战三 :验证 enumerate

  • 代码流程如下:
  1. 测试 enumerate(Thread list[]) ,复制group下面的线程
  2. 测试 enumerate(ThreadGroup list[]) ,复制整个group
  3. 测试发现是浅复制
public static void testCopy() throws Exception {
      ThreadGroup group1 = new ThreadGroup("Group1");
      System.out.println("----");


      Thread t1 = new Thread(group1, () -> {
          Scanner sc = new Scanner(System.in);
          System.out.println("点击任意键唤醒线程 ...");
          sc.nextLine();
      });
      Thread t2 = new Thread(group1, () -> {
          Scanner sc = new Scanner(System.in);
          System.out.println("点击任意键唤醒线程 ...");
          sc.nextLine();

      });
      Thread t3 = new Thread(group1, () -> {
          Scanner sc = new Scanner(System.in);
          System.out.println("点击任意键唤醒线程 ...");
          sc.nextLine();
      });

      group1.list();
      System.out.println("group1.size ->  " + group1.activeCount());

      Thread.sleep(1000);
      System.out.println("----");

      t1.start();
      t2.start();
      t3.start();

      /*
          2. 开始 copy ,保留原 group
          复制threads
       */
      System.out.println("=== 2. begin to copy === ");
      Thread[] threads = new Thread[group1.activeCount()];
      group1.enumerate(threads);
      // 上面仅仅是复制,没有启动。
      System.out.println("group1.size ->  " + group1.activeCount());
      System.out.println("----");
      Arrays.stream(threads).forEach(System.out::println);

      Thread.sleep(1000);

      System.out.println(threads[0] == t1);
      System.out.println(threads[1] == t2);
      System.out.println(threads[2] == t3);
      System.out.println("threads 复制 enumerate 仅仅是浅复制 ...");
      System.out.println("group1.size ->  " + group1.activeCount());
      System.out.println("----");

      Thread.sleep(1000);

      /*
          复制 group
       */
      System.out.println("=== 第二波复制 ===");
      System.out.println("Thread.currentThread().getThreadGroup().activeGroupCount() -> " +
              Thread.currentThread().getThreadGroup().activeGroupCount());
      Thread.currentThread().getThreadGroup().list();
      ThreadGroup[] groups = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];

      Thread.currentThread().getThreadGroup().enumerate(groups);
      // 上面仅仅是复制,没有启动。
      System.out.println("----");

      Thread.sleep(1000);
      System.out.println("=== 复制完了 ===");
      for (ThreadGroup group :
              groups) {
          group.list();
      }

      System.out.println("groups[0] == group1 ? " + (groups[0] == group1));
      System.out.println("group 复制 enumerate 仅仅是浅复制 ...");
      System.out.println("group1.size ->  " + group1.activeCount());
      System.out.println("----");
  }

输出:

----
java.lang.ThreadGroup[name=Group1,maxpri=10]
group1.size ->  0
----
=== 2. begin to copy === 
group1.size ->  3
----
Thread[Thread-0,5,Group1]
Thread[Thread-1,5,Group1]
Thread[Thread-2,5,Group1]
点击任意键唤醒线程 ...
点击任意键唤醒线程 ...
点击任意键唤醒线程 ...
true
true
true
enumerate 仅仅是浅复制 ...
group1.size ->  3
----
=== 第二波复制 ===
Thread.currentThread().getThreadGroup().activeGroupCount() -> 1
java.lang.ThreadGroup[name=main,maxpri=10]
    Thread[main,5,main]
    Thread[Monitor Ctrl-Break,5,main]
    java.lang.ThreadGroup[name=Group1,maxpri=10]
        Thread[Thread-0,5,Group1]
        Thread[Thread-1,5,Group1]
        Thread[Thread-2,5,Group1]
----
=== 复制完了 ===
java.lang.ThreadGroup[name=Group1,maxpri=10]
    Thread[Thread-0,5,Group1]
    Thread[Thread-1,5,Group1]
    Thread[Thread-2,5,Group1]
groups[0] == group1 ? true
enumerate 仅仅是浅复制 ...
group1.size ->  3
----
...
(输入任意键,线程结束)
  • 结论:浅层复制,只是引用复制。

=== 点击查看top目录 ===

2.4 实战四:测试默认 ThreadGroup

  • 代码
    public static void test01() throws Exception {
        print();
        new Thread(() -> print(),"A1").start();
        new Thread(() -> new Thread(() -> print(),"B2").start(),"B1").start();
    }
	public static void print(){
       System.out.println("currentThread -> " + Thread.currentThread() + ",group -> " + Thread.currentThread().getThreadGroup());
    }
  • 输出
currentThread -> Thread[main,5,main],group -> java.lang.ThreadGroup[name=main,maxpri=10]
currentThread -> Thread[A1,5,main],group -> java.lang.ThreadGroup[name=main,maxpri=10]
currentThread -> Thread[B2,5,main],group -> java.lang.ThreadGroup[name=main,maxpri=10]
  • 结论: 不指定 group 的情况下,deamon 、priority 参数随父 thread。

=== 点击查看top目录 ===

2.5 实战五:测试 Exception 捕获

  • 代码
public static void testCatchException() throws Exception{
        ThreadGroup g1 = new ThreadGroup("ThreadGroup");
        Thread t1 = new Thread(g1, () -> { throw new RuntimeException(Thread.currentThread() + "自定义的一个RuntimeException...");});
        t1.start();

        Thread.sleep(1000);

        CatchExceptinoThreadGroup g2 = new CatchExceptinoThreadGroup("CatchExceptionThreadGroup");
        Thread t2 = new Thread(g2, () -> { throw new RuntimeException(Thread.currentThread() + "自定义的一个RuntimeException...");});
        t2.start();
 }
    
 public static class CatchExceptinoThreadGroup extends ThreadGroup{
      public CatchExceptinoThreadGroup(String name) {
          super(name);
      }
      public CatchExceptinoThreadGroup(ThreadGroup parent, String name) {
          super(parent, name);
      }
      @Override
      public void uncaughtException(Thread t, Throwable e) {
          // 这里可以写 if else 处理各种各样的异常
          if(e instanceof RuntimeException){
              System.out.println("### CatchExceptinoThreadGroup catch " + e);
          }
      }
  }
  • 输出
Exception in thread "Thread-0" java.lang.RuntimeException: Thread[Thread-0,5,ThreadGroup]自定义的一个RuntimeException...
	at indi.sword.util.basic.Thread._06_01_TestThreadGroup.lambda$testCatchException$15(_06_01_TestThreadGroup.java:291)
	at java.lang.Thread.run(Thread.java:748)
### CatchExceptinoThreadGroup catch java.lang.RuntimeException: Thread[Thread-1,5,CatchExceptionThreadGroup]自定义的一个RuntimeException...

  • 解析
  1. g1 线程组(默认组),group内线程抛出异常,无法在外头捕获
  2. g2 线程组 (重写组),group内线程抛出异常,被外层捕获到了
  • 结论:可以重写 uncaughtException 方法来进行异常的捕获。关于 Thread.UncaughtExceptionHandler 下一章节进行讲解。

=== 点击查看top目录 ===

三、源码剖析

3.1 Class 类初始化

3.1.1 demo
Thread t1 = new Thread(group1, () -> {
          Scanner sc = new Scanner(System.in);
          System.out.println("点击任意键唤醒线程 ...");
          sc.nextLine();
      });

=== 点击查看top目录 ===

3.1.2 Thread 构造方法
  • java.lang.Thread#Thread(java.lang.Runnable, java.lang.String)
public Thread(Runnable target) {
       init(null, target, "Thread-" + nextThreadNum(), 0);
   }

=== 点击查看top目录 ===

3.1.3 init 方法
  • java.lang.Thread#init(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String, long)
 private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }
  • java.lang.Thread#init(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String, long, java.security.AccessControlContext, boolean)
private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;
        //当前线程就是该线程的父线程
        Thread parent = currentThread();
        //获取系统的security
        SecurityManager security = System.getSecurityManager();
        // 如果没有传入group
        if (g == null) {
            /* Determine if it's an applet or not */

            /* If there is a security manager, ask the security manager
               what to do. */
            //security不为null时,线程所在group为security的group
            if (security != null) {
                g = security.getThreadGroup();
            }

            /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
            //security为null时,直接使用父线程的group
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
        g.checkAccess();

        /*
         * Do we have the required permissions?
         */
        //授权
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }

        g.addUnstarted();

        this.group = g;
        //将守护线程、优先级等设置为父线程的对应属性
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        this.target = target;
        setPriority(priority);
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            //创建线程共享变量副本
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        //分配线程id
        tid = nextThreadID();
    }

分析:

  1. 若 group 没有指定,那么使用的是父线程的 group ,daemon 与 priority 参数都跟随父类。
  2. if (inheritThreadLocals && parent.inheritableThreadLocals != null) 这个具体看上一篇【线程】InheritableThreadLocal 剖析 (十六)

=== 点击查看top目录 ===

3.2 activeCount 方法

  • java.lang.ThreadGroup#activeCount
  • 活跃 thread 数
public int activeCount() {
        int result;
        // Snapshot sub-group data so we don't hold this lock
        // while our children are computing.
        int ngroupsSnapshot;
        ThreadGroup[] groupsSnapshot;
        synchronized (this) {
            if (destroyed) {
                return 0;
            }
            result = nthreads; // 获取线程数
            ngroupsSnapshot = ngroups;
            if (groups != null) {
                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
            } else {
                groupsSnapshot = null;
            }
        }
        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
            result += groupsSnapshot[i].activeCount();
        }
        return result;
    }

  • 解析:
  1. synchronized 方法块,确保线程安全
  2. 递归统计。(result = nthreads; // 获取线程数)

=== 点击查看top目录 ===

3.3 activeGroupCount 方法

  • java.lang.ThreadGroup#activeGroupCount
 public int activeGroupCount() {
        int ngroupsSnapshot;
        ThreadGroup[] groupsSnapshot;
        synchronized (this) {
            if (destroyed) {
                return 0;
            }
            ngroupsSnapshot = ngroups;
            if (groups != null) {
                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
            } else {
                groupsSnapshot = null;
            }
        }
        int n = ngroupsSnapshot; // 获取 group 数
        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
            n += groupsSnapshot[i].activeGroupCount(); // 递归 
        }
        return n;
    }
  • 解析:
  1. synchronized 方法块,确保线程安全
  2. 递归统计。(int n = ngroupsSnapshot; // 获取 group 数 )

=== 点击查看top目录 ===

3.4 list 方法

  • 用于打印操作
  • java.lang.ThreadGroup#list()
public void list() {
        list(System.out, 0);
    }
  • java.lang.ThreadGroup#list(java.io.PrintStream, int) 方法
void list(PrintStream out, int indent) {
        int ngroupsSnapshot;
        ThreadGroup[] groupsSnapshot;
        synchronized (this) {
            for (int j = 0 ; j < indent ; j++) {
                out.print(" ");
            }
            out.println(this);
            indent += 4;
            for (int i = 0 ; i < nthreads ; i++) {
                for (int j = 0 ; j < indent ; j++) {
                    out.print(" ");
                }
                out.println(threads[i]);
            }
            ngroupsSnapshot = ngroups;
            if (groups != null) {
                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
            } else {
                groupsSnapshot = null;
            }
        }
        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
            groupsSnapshot[i].list(out, indent); //递归
        }
    }
  • 解析:
  1. synchronized 方法块,确保线程安全
  2. 参数 PrintStream 指定输出流,默认控制台 (System.out,)
  3. 参数 indent ,打印前置多少个空格,目的是为了层级显示。
  4. groupsSnapshot[i].list(out, indent); 递归进行 list 打印操作。

=== 点击查看top目录 ===

3.5 enumerate 方法

  • java.lang.ThreadGroup#enumerate(java.lang.Thread[])
  • 用于复制操作
    public int enumerate(Thread list[]) {
        checkAccess();
        return enumerate(list, 0, true);
    }

  • java.lang.ThreadGroup#enumerate(java.lang.Thread[], int, boolean) 方法
private int enumerate(Thread list[], int n, boolean recurse) {
        int ngroupsSnapshot = 0;
        ThreadGroup[] groupsSnapshot = null;
        synchronized (this) {
            if (destroyed) {
                return 0;
            }
            int nt = nthreads;
            if (nt > list.length - n) {
                nt = list.length - n;
            }
            for (int i = 0; i < nt; i++) {
                if (threads[i].isAlive()) {
                    list[n++] = threads[i];
                }
            }
            if (recurse) {
                ngroupsSnapshot = ngroups;
                if (groups != null) {
                    groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
                } else {
                    groupsSnapshot = null;
                }
            }
        }
        if (recurse) {
            for (int i = 0 ; i < ngroupsSnapshot ; i++) {
                n = groupsSnapshot[i].enumerate(list, n, true); //递归
            }
        }
        return n;
    }
  • 解析:
  1. synchronized 方法块,确保线程安全
  2. Arrays.copyOf 进行复制(最终调用Native方法 java.lang.System#arraycopy )
  3. groupsSnapshot[i].enumerate(list, n, true); 递归进行复制

=== 点击查看top目录 ===

3.6 interrupt 方法

  • java.lang.ThreadGroup#interrupt
public final void interrupt() {
        int ngroupsSnapshot;
        ThreadGroup[] groupsSnapshot;
        synchronized (this) {
            checkAccess();
            for (int i = 0 ; i < nthreads ; i++) {
                threads[i].interrupt();
            }
            ngroupsSnapshot = ngroups;
            if (groups != null) {
                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
            } else {
                groupsSnapshot = null;
            }
        }
        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
            groupsSnapshot[i].interrupt(); //递归
        }
    }
  • 解析:
  1. synchronized 方法块,确保线程安全
  2. groupsSnapshot[i].interrupt(); 内部递归调用 interrupt

=== 点击查看top目录 ===

3.7 uncaughtException 方法

    public void uncaughtException(Thread t, Throwable e) {
        if (parent != null) {
            parent.uncaughtException(t, e);
        } else {
            Thread.UncaughtExceptionHandler ueh =
                Thread.getDefaultUncaughtExceptionHandler();
            if (ueh != null) {
                ueh.uncaughtException(t, e);
            } else if (!(e instanceof ThreadDeath)) {
                System.err.print("Exception in thread \""
                                 + t.getName() + "\" ");
                e.printStackTrace(System.err);
            }
        }
    }
  • 解析:
  1. 对于子Thread抛出的Exception,递归交由父 ThreadGroup 定义的 uncaughtException 方法来处理。

四、番外篇

下一章节:【线程】Thread.UncaughtExceptionHandler 实战与剖析 (十八)
上一章节:【线程】InheritableThreadLocal 剖析 (十六)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章