zoukankan      html  css  js  c++  java
  • JAVA篇:Java 多线程 (四) 线程组ThreadGroup

    4、线程组ThreadGroup

    4.1 什么是线程组

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

    或许需要区分一下线程数组、线程池、线程组ThreadGroup。

    线程数组就是将线程放入数组中,方便做一些简单的操作(遍历查询、运行、join阻塞)。

    线程池的概念是在python线程接触的,由于python的线程提供了通用线程调用方法的方式来替代线程继承创建,可以维持一个一定数量的线程数组以供使用,减少线程频繁创建销毁的开销,原理类似于数据库连接池。这个用法Java好像并不常用。

    还有就是线程组ThreadGroup,它所维持的线程结构更像是一个树,提供了一些管理线程组的方法。

     

    4.2 ThreadGroup的构造方法

    ThreadGroup和Thread一样定义在java.lang下面,提供了两个构造函数,其中一个构造函数可指定父线程组。

    //构造方法1:构造新线程组,新线程组的默认父项是正在运行线程所在的线程组
    ThreadGroup(String name)
    //构造方法2:构造新线程组,并将指定线程组作为父线程组
    ThreadGroup(ThreadGroup parent, String name)
        public static void test1(){
            ThreadGroup threadGroup1 = new ThreadGroup("线程组1");
            System.out.println(threadGroup1.getName());//线程组1
            System.out.println(threadGroup1.getParent().getName());//main
        }

    ThreadGroup提供了方法checkAccess(),用来确定当前运行的线程是否有权限修改此线程组。当用户在使用构建方法在默认或指定线程组下构建新的线程组,会调用该方法,检查当前线程是否有权限修改父线程组,若没有权限,会抛出错误“SecurityException”。

    4.3 ThreadGroup提供的一些方法

    ThreadGroup的方法与Thread向对应,只是提供了一些统一的管理操作的方法。

    1. String getName():返回此线程组的名称。

    2. ThreadGroup getParent():返回此线程组的父级。

    3. boolean parentOf(ThreadGroup g):测试此线程组是否是其祖先线程组之一。

    4. void interrupt():中断此线程组中的所有线程。

    5. void setMaxPriority(int pri):设置组的最大优先级。

    6. int getMaxPriority():返回此线程组的最大优先级。

    7. void setDaemon(boolean daemon):更改此线程组的守护程序状态。守护线程组最后一个线程停止或最后一个线程组被销毁时自动销毁。

    8. boolean isDaemon():测试此线程组是否是守护线程组。

    9. void destroy():销毁此线程组及其所有子组, 此线程组必须为空,表示此线程组中的所有线程已停止。如果线程组不为空或线程组已被破坏,则抛出"IllegalThreadStateException"。

    10. boolean isDestroyed():测试此线程组是否已被破坏。

    11. int activeCount():返回此线程组及其子组中活动线程数的估计。

    12. int activeGroupCount():返回此线程组及其子组中活动组数的估计。

    13. void checkAccess():确定当前运行的线程是否有权限修改此线程组。在ThreadGroup中涉及任意线程、线程组的操作都需要对这些线程线程组的权限进行检查,若无权限都会抛出“SecurityException”

    14. int enumerate(Thread[] list):将此线程组及其子组中的每个活动线程复制到指定的数组中。相当于enumerate(Thread[] list, true)

    15. int enumerate(Thread[] list, boolean recurse):若recurse为true,递归将此线程组中的每个活动线程复制到指定的数组中。

    16. int enumerate(ThreadGroup[] list):复制到该线程组及其子组中每个活动子组的指定数组引用。

    17. int enumerate(ThreadGroup[] list, boolean recurse):复制到该线程组中每个活动子组的指定数组引用。

    18. void list():将有关此线程组的信息打印到标准输出。

    19. String toString():返回此Thread组的字符串表示形式。

    20. void uncaughtException(Thread t, Throwable e):当此线程组中的线程因为一个未捕获的异常由Java Virtual Machine调用,而线程不具有特定Thread.UncaughtExceptionHandler安装。

    21. void resume():已弃用,这种方法仅与Thread.suspend和ThreadGroup.suspend一起使用 ,这两种方法都已经被弃用,因为它们本身就是死锁的。 详见Thread.suspend() 。

    22. void stop():已弃用,这种方法本质上是不安全的。 详见Thread.stop() 。

    23. void suspend():已弃用,这种方法本质上是死锁的。 详见Thread.suspend() 。

    24. boolean allowThreadSuspension(boolean b):已弃用,此呼叫的定义取决于suspend() ,它已被弃用。 此外,从未指定此调用的行为。

    4.4 测试代码

    代码

        public  void test1(){
            System.out.println(String.format("主线程:获取主线程的父线程组名字%s",Thread.currentThread().getThreadGroup().getParent().getName()));
            /* 创建线程组树 */
            System.out.println("*****创建线程组树1作为2、3父项,2作为4父项");
            ThreadGroup threadGroup1 = new ThreadGroup("线程组1");
            ThreadGroup threadGroup2 = new ThreadGroup(threadGroup1,"线程组2");
            ThreadGroup threadGroup3 = new ThreadGroup(threadGroup1,"线程组3");
            ThreadGroup threadGroup4 = new ThreadGroup(threadGroup2,"线程组4");
            System.out.println(String.format("主线程:线程组1是否是线程组2的父线程组%b",threadGroup1.parentOf(threadGroup2)));
            System.out.println(String.format("主线程:线程组1是否是线程组4的父线程组%b",threadGroup1.parentOf(threadGroup4)));
            System.out.println(String.format("主线程:线程组3是否是线程组4的父线程组%b",threadGroup3.parentOf(threadGroup4)));
    ​
            /* 创建线程组中的子线程,线程组1:1,线程组2:1,线程组3:1,线程组4:3 */
            System.out.println("*****创建线程组中的子线程,线程组1:1,线程组2:1,线程组3:1,线程组4:3,并运行");
            Thread[] threads = new Thread[6];
           threads[0]= new myThread(threadGroup1,"线程组1-线程1");
           threads[1]= new myThread(threadGroup2,"线程组2-线程2");
           threads[2]= new myThread(threadGroup3,"线程组3-线程3");
           threads[3]= new myThread(threadGroup4,"线程组4-线程41");
           threads[4]= new myThread(threadGroup4,"线程组4-线程42");
           threads[5]= new myThread(threadGroup4,"线程组4-线程43");
    ​
            for(int i=0;i<6;i++){
                threads[i].start();
            }
    ​
            /* 将线程组1,2,3都设置为守护线程组 */
            System.out.println("*****将线程组1,2,3都设置为守护线程组");
            threadGroup1.setDaemon(true);
            threadGroup2.setDaemon(true);
            threadGroup3.setDaemon(true);
    ​
            System.out.println(String.format("主线程:线程组1是否是守护线程%b",threadGroup1.isDaemon()));
            System.out.println(String.format("主线程:线程组3是否是守护线程%b",threadGroup3.isDaemon()));
            System.out.println(String.format("主线程:线程组4是否是守护线程%b",threadGroup4.isDaemon()));
    ​
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    ​
            /* 复制线程组先全部子线程到数组*/
            System.out.println("*****复制线程组先全部活动子线程到数组并遍历");
            Thread[] threads2 = new Thread[threadGroup1.activeCount()];
            int tc = threadGroup1.enumerate(threads2);
            System.out.println(String.format("主线程:线程组1中%d个子线程成功复制到线程数组threads",tc));
            for(int i=0;i<tc;i++){
                System.out.println(threads2[i]);
            }
    ​
    ​
    ​
            /*  中断全部等待的子线程 */
            System.out.println("*****中断全部等待的子线程");
            threadGroup1.interrupt();
    ​
            for(int i=0;i<tc;i++){
                try {
                    threads2[i].join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("*****所有子线程运行完毕并销毁");
            System.out.println(String.format("主线程:线程组1下运行线程估计%d",threadGroup1.activeCount()));
            System.out.println(String.format("主线程:线程组1下运行线程组估计%d",threadGroup1.activeGroupCount()));
    ​
            System.out.println("*****线程组1,2,3作为守护线程,线程组3会自动销毁,1和2会因为4无法销毁");
    ​
            System.out.println(String.format("主线程:线程组1是否被销毁%b",threadGroup1.isDestroyed()));
            System.out.println(String.format("主线程:线程组3是否被销毁%b",threadGroup3.isDestroyed()));
            System.out.println(String.format("主线程:线程组4是否被销毁%b",threadGroup4.isDestroyed()));
    ​
            System.out.println("*****手动销毁线程组4");
            threadGroup4.destroy();
            System.out.println(String.format("主线程:线程组1是否被销毁%b",threadGroup1.isDestroyed()));
    ​
    ​
    ​
        }
    ​
        class myThread extends Thread{
            public myThread(ThreadGroup tg,String name){
                super(tg,name);
            }
            @Override
            public void run(){
                synchronized ("A"){
                    System.out.println(String.format("子线程 %s:调用wait()进入休眠",getName()));
                    try {
                        "A".wait();
                    } catch (InterruptedException e) {
                        System.out.println(String.format("子线程 %s:被中断!",getName()));
                    }
                }
    ​
            }
    ​
        }

    运行结果

    主线程:获取主线程的父线程组名字system
    *****创建线程组树1作为2、3父项,2作为4父项
    主线程:线程组1是否是线程组2的父线程组true
    主线程:线程组1是否是线程组4的父线程组true
    主线程:线程组3是否是线程组4的父线程组false
    *****创建线程组中的子线程,线程组1:1,线程组2:1,线程组3:1,线程组4:3,并运行
    *****将线程组1,2,3都设置为守护线程组
    主线程:线程组1是否是守护线程true
    子线程 线程组1-线程1:调用wait()进入休眠
    主线程:线程组3是否是守护线程true
    子线程 线程组4-线程42:调用wait()进入休眠
    主线程:线程组4是否是守护线程false
    子线程 线程组3-线程3:调用wait()进入休眠
    子线程 线程组4-线程41:调用wait()进入休眠
    子线程 线程组2-线程2:调用wait()进入休眠
    子线程 线程组4-线程43:调用wait()进入休眠
    *****复制线程组先全部活动子线程到数组并遍历
    主线程:线程组1中6个子线程成功复制到线程数组threads
    Thread[线程组1-线程1,5,线程组1]
    Thread[线程组2-线程2,5,线程组2]
    Thread[线程组4-线程41,5,线程组4]
    Thread[线程组4-线程42,5,线程组4]
    Thread[线程组4-线程43,5,线程组4]
    Thread[线程组3-线程3,5,线程组3]
    *****中断全部等待的子线程
    子线程 线程组1-线程1:被中断!
    子线程 线程组3-线程3:被中断!
    子线程 线程组4-线程41:被中断!
    子线程 线程组4-线程42:被中断!
    子线程 线程组4-线程43:被中断!
    子线程 线程组2-线程2:被中断!
    *****所有子线程运行完毕并销毁
    主线程:线程组1下运行线程估计0
    主线程:线程组1下运行线程组估计2
    *****线程组1,2,3作为守护线程,线程组3会自动销毁,1和2会因为4无法销毁
    主线程:线程组1是否被销毁false
    主线程:线程组3是否被销毁true
    主线程:线程组4是否被销毁false
    *****手动销毁线程组4
    主线程:线程组1是否被销毁true

    解析

    • 主线程main所属线程组的父线程组是system

    • 创建了线程组树如下

     

    • 创建了6个子线程,结构如下,并运行所有子线程,所有子线程进入wait状态,使得所有子线程在下面的代码运行时一直处于活动状态

       

    • 将线程组1、2、3都设置为守护线程组,线程组4为非守护线程组

    • 调用threadGroup1.enumerate(threads2)成功将线程组1及其子组下全部活动线程复制到threads2数组中

    • 通过interrupt中断线程组1及其子组下全部线程

    • 所有子线程运行完毕销毁后,作为守护线程,线程组3直接销毁,线程组4不是守护线程所以不会自动销毁,线程组1,2因为还有子线程组未销毁,不会自动销毁

       

    • 手动销毁线程组4,线程组1、2自动销毁

     

     

     

     

    4.X 参考

    Java并发 之 线程组 ThreadGroup 介绍

    线程组ThreadGroup分析详解 多线程中篇(三)

    Java多线程16:线程组

     

    0、JAVA多线程编程

    Java多线程编程所涉及的知识点包含线程创建、线程同步、线程间通信、线程死锁、线程控制(挂起、停止和恢复)。之前 JAVA篇:Java的线程仅仅了解了部分线程创建和同步相关的小部分知识点,但是其实在编程过程中遇到的事情并不仅仅限于此,所以进行整理,列表如下:

    当你深入了解,你就会发现世界如此广袤,而你对世界的了解则是如此浅薄,请永远保持谦卑的态度。
  • 相关阅读:
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第50章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第49章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第48章 读书笔记(待更新)
    Spring Boot 中使用 Quartz 实现任务调度
    实战 FastDFS Java 客户端上传文件
    分布式文件系统之 FastDFS
    Java 持久层框架之 MyBatis
    C语言实现贪吃蛇
    [转载]分享三篇非常好的学习心得
    selenium加载cookie报错问题:selenium.common.exceptions.InvalidCookieDomainException: Message: invalid cookie domain
  • 原文地址:https://www.cnblogs.com/liwxmyself/p/15411892.html
Copyright © 2011-2022 走看看