线程组

JDK 对线程组类注释:

A thread group represents a set of threads. In addition, a thread group can also include other thread groups. The thread groups form a tree in which every thread group except the initial thread group has a parent. A thread is allowed to access information about its own thread group, but not to access information about its thread group’s parent thread group or any other thread groups.

可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程,
这样的组织结构有点类似于树的形式,如图所示.

线程组的作用是:可以批量管理线程或线程组对象,有效地对线程或线程组对象进行组织
3.jpg

线程关联线程组:1级关联

所谓1级关联就是父对象中有子对象,但并不创建孙对象。
这种情况在开发中很常见,比如创建一些线程时,为了有效对这些线程进行阻止管理,通常情况下是创建一个线程组,
然后再将部分线程归属到该组中,以此来对零散的线程对象进行有效的管理。

看一下简单的1级关联的例子:

  1. public class ThreadGroupTest1 implements Runnable {
  2. public void run() {
  3. try {
  4. while (!Thread.currentThread().isInterrupted()) {
  5. System.out.println("ThreadName = " + Thread.currentThread().getName());
  6. Thread.sleep(3000);
  7. }
  8. } catch (InterruptedException e) {
  9. e.printStackTrace();
  10. }
  11. }
  12. public static void main(String[] args){
  13. ThreadGroup tg = new ThreadGroup("新建线程组1");
  14. new Thread(tg, new ThreadGroupTest1()).start();
  15. new Thread(tg, new ThreadGroupTest1()).start();
  16. System.out.println("活动的线程数为:" + tg.activeCount());
  17. System.out.println("线程组的名称为:" + tg.getName());
  18. }
  19. }
  20. /*
  21. ---------------------运行结果-------------------------
  22. 活动的线程数为:2
  23. ThreadName = Thread-0
  24. 线程组的名称为:新建线程组1
  25. ThreadName = Thread-1
  26. ThreadName = Thread-0
  27. ThreadName = Thread-1
  28. ThreadName = Thread-0
  29. */

activeCount()方法可以返回线程组中的所有活动线程数,包含下面的所有子孙节点的线程,
由于线程组中的线程是动态变化的,这个值只能是一个估算值
**


线程关联线程组:多级关联

所谓的多级关联就是父对象中有子对象,子对象中再创建子对象买也就出现了子孙的效果了。但是这种写法在开发中不太常见,因为线程树如果涉及得复杂反而不利于线程对象的管理,不过JDK确实提供了多级关联的线程树结构。
多级关联的代码就不写了,简单看一下怎么使用关机关联,查看下JDK API的ThreadGroup构造方法:
6. 线程组 - 图2

注意一下第二个,假如要使用多级关联一般就是用第二个构造函数。第一个参数表示新线程组的父线程组,第二个参数表示新线程组的名称,有了父线程组和新线程组的名称,自然可以构造出一个新的线程组来了。
当然用第一个构造方法也是可以的,下一部分就会提到。
另外注意一点,线程必须启动后才能归到指定线程组中


线程组自动归属特性

自动归属的意思就是自动归到当前线程组中,看一下例子:
image.png

从结果看,实例化了一个group出来,没有指定线程组,那么自动归到当前线程所属的线程组中
也就是隐式地在一个线程组中添加了一个子线程组。


根线程组

获取根线程组

  1. public static void main(String[] args) {
  2. System.out.println(Thread.currentThread().getThreadGroup().getParent().getName());
  3. System.out.println(Thread.currentThread().getThreadGroup().getParent().getParent().getName());
  4. }
  5. /*---------------运行结果-----------------
  6. system
  7. Exception in thread "main" java.lang.NullPointerException
  8. at ThreadGroupTest1.main(ThreadGroupTest1.java:16)*/

运行结果可以得出两个结论:
1、根线程组就是系统线程组system
2、抛空指针异常是因为系统线程组上已经没有线程组了,所以system的getParent()方法返回的是null,
对null调用getName()方法自然是NullPointerException

关于根线程组,看一下ThreadGroup的源码:
image.png


批量停止组内线程

调用线程组interrupt(),会将线程组树下的所有子孙线程中断标志置为true,可以用来批量中断线程。

public class ThreadGroupTest1 extends Thread
{
    public ThreadGroupTest1(ThreadGroup tg, String name){
        super(tg, name);
    }

    public void run(){
        System.out.println("ThreadName = " + Thread.currentThread().getName()
            +"准备开始死循环了");
        while (!this.isInterrupted()){

        }
        System.out.println("ThreadName = " + Thread.currentThread().getName()
            +"结束了");
    }

    public static void main(String[] args) throws InterruptedException
    {
        ThreadGroup tg = new ThreadGroup("我的线程组");
        ThreadGroupTest1 t1 = null;
        for (int i = 0; i < 3; i++){
            new ThreadGroupTest1(tg, "线程" + i).start();
        }
        Thread.sleep(5000);
        tg.interrupt();
        System.out.println("调用了interrupt()方法");
    }
}


/*
-----------运行结果-------------
ThreadName = 线程1准备开始死循环了
ThreadName = 线程0准备开始死循环了
ThreadName = 线程2准备开始死循环了
调用了interrupt()方法
ThreadName = 线程1结束了
ThreadName = 线程2结束了
ThreadName = 线程0结束了*/