ThreadGroup API介绍

ThreadGroup API介绍

TreadGroup其实是在1.5之前用的比较多,在没有线程池API前都使用TreadGroupApi来管理线程池。虽然现在有线程池API来供大家使用,但是如果在平时开发中只想启用三五个线程,那么可以选择使用TreadGroup来管理线程。

我们找到ThreadGroup来看一下:

线程组表示一组线程。此外,线程组还可以包括其他线程组。线程组形成一个树,其中除了初始线程组外,每个线程组都有一个父线程组。

允许线程访问关于其自己线程组的信息,但不允许访问关于其线程组的父线程组或任何其他线程组的信息。

那么,允许线程访问关于其自己线程组的信息的信息都是什么呢?我们接下来看一下:

首先创建一个threadgroup

public class ThreadGroupCreate {
    public static void main(String[] args) {
        // 1. use the name
        ThreadGroup tg1 = new ThreadGroup("TG1");
        Thread t1 = new Thread(tg1, () -> {
            while (true) {
                try {
                    Thread.sleep(10_000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "T1");
        t1.start();
        System.out.println("t1's thread group name = " + t1.getThreadGroup().getName());// TG1
        //todo  2. use the parent and group name
    }
}

运行效果如下:

打印一下当前threadgroup的名字和他父级的名字:

ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
System.out.println(threadGroup.getName());
System.out.println(threadGroup.getParent());

运行效果如下:

可以看到他的线程组是TG1,他的夫级线程组是main,并且main线程的优先级很高是10。

接下来我们给创建另一个线程组,他的夫级线程组TG1:

//2. use the parent and group name
ThreadGroup tg2 = new ThreadGroup(tg1, "TG2");
System.out.println("tg2's name = " + tg2.getName());
System.out.println("tg2's parent name = " + tg2.getParent().getName());

运行效果如下:

线程组两种创建方式就ok了,我们再来验证一下:允许线程访问关于其自己线程组的信息,但不允许访问关于其线程组的父线程组或任何其他线程组的信息

//TG2 访问TG1
ThreadGroup tg2 = new ThreadGroup(tg1, "TG2");
Thread t2 = new Thread(tg2,()->{
    System.out.println("tg2's parent threadgroup is"+tg2.getName());
});
t2.start();

// TG3与TG1为同一个父ThreadGroup-main
// 测试TG3能否访问TG1的一些信息
ThreadGroup tg3 = new ThreadGroup("TG3");
Thread t3 = new Thread(tg3, () -> {
    System.out.println(">>>>" + t1.getName());// TG1
    Thread[] threads = new Thread[tg1.activeCount()];
    tg1.enumerate(threads);
    Stream.of(threads).forEach(System.out::println);// Thread[T1,5,TG1]
}, "T3");
t3.start();

运行效果如下:

可以看到其实是可以访问的,可能是官方文档有问题,也有可能是我翻译的有问题。。。

接下来学习几个ThreadGroup的常用方法:

activeCount()

返回此线程组及其子组中活动线程的评估数量。这里注意是评估数量,因为可能获取的时候,某个线程消亡了或者正在被添加。

public class ThreadGroupAPI {
    public static void main(String[] args) {
        ThreadGroup tg1 = new ThreadGroup("TG1");
        Thread t1 = new Thread(tg1, () -> {
            while (true) {
                try {
                    Thread.sleep(1_000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }, "T1");
        /*tg1.setDaemon(true);*/
        t1.start();

        ThreadGroup tg2 = new ThreadGroup(tg1, "TG2");
        Thread t2 = new Thread(tg2, () -> {
            while (true) {
                try {
                    Thread.sleep(1_000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }, "T2");
        t2.start();

        System.out.println("tg1 active count is " + tg1.activeCount());
    }
}

运行效果如下:

activeGroupCount()

返回此线程组及其子组中活动组的评估数量。

System.out.println(tg1.activeGroupCount());

运行效果如下:

checkAccess()

确定当前运行的线程是否具有修改此线程组的权限。

代码如下:

tg1.checkAccess();

运行效果如下:

没抛出异常代表有权限修改线程组。

destroy()

销毁这个线程组及其所有子组。destroy前需要确定线程组里没有活跃的线程。如果线程组不为空或线程组已被销毁将抛出IllegalThreadStateException

代码如下:

tg1.destroy();

运行效果如下:

因为我们线程里有while,所以是活跃的线程,这里就抛出异常了。

enumerate(Thread[] list)

将此线程组及其子组中的每个活动线程复制到指定的数组中。

代码如下:

Thread[] ts1 = new Thread[tg1.activeCount()];
tg1.enumerate(ts1);
System.out.println(Arrays.toString(ts1));

运行效果如下:

enumerate(Thread[] list, boolean recurse)

将此线程组中的每个活动线程复制到指定数组中。

代码如下:

Thread[] ts2 = new Thread[tg1.activeCount()];
tg1.enumerate(ts2, false);
System.out.println(Arrays.toString(ts2));

运行效果如下:

如果为真,则递归枚举此线程组的所有子组。那么我们使用false试试:

ThreadGroup mainThreadGroup = Thread.currentThread().getThreadGroup();
Thread[] ts3 = new Thread[mainThreadGroup.activeCount()];
mainThreadGroup.enumerate(ts3, false);
System.out.println(Arrays.toString(ts3));

运行效果如下:

interrupt()

中断此线程组中的所有线程。

代码如下:

tg1.interrupt();

运行效果如下:

setDaemon(boolean daemon)

守护进程——如果为真,则将此线程组标记为守护线程组;否则,将此线程组标记为normal。

 ThreadGroup tg1 = new ThreadGroup("TG1");
    Thread t1 = new Thread(tg1, () -> {
        try {
            Thread.sleep(1_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }, "T1");
    tg1.setDaemon(true);
    t1.start();
    Thread.sleep(2_000);
    System.out.println(tg1.isDestroyed());

运行效果如下:

注释tg1.setDaemon(true);试一下:

手动销毁一下:

ThreadGroup tg1 = new ThreadGroup("TG1");
Thread t1 = new Thread(tg1, () -> {
    try {
        Thread.sleep(1_000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}, "T1");
//tg1.setDaemon(true);
t1.start();
Thread.sleep(2_000);
System.out.println(tg1.isDestroyed());
tg1.destroy();
System.out.println(tg1.isDestroyed());

运行效果如下:

这篇随笔是我周六没吃早饭没吃午饭弄到下午4点38才弄完的,内容虽然你不多但是改来改去,时间也就慢慢过去了,中间多少次想休息一会吃个饭再继续弄,但是还是想弄完了再好好吃饭,也许这样下去永远都胖不起来吧。。。哎精神粮食充实啊~

posted @ 2020-09-19 16:49  风暴松鼠  阅读(185)  评论(0)    收藏  举报