多线程系列(十七) -线程组介绍

一、简介

在之前的多线程系列文章中,我们陆陆续续的介绍了Thread线程类相关的知识和用法,其实在Thread类上还有一层ThreadGroup类,也就是线程组。

今天我们就一起来简单的聊聊线程组相关的知识和用法。

二、什么是线程组

线程组,简单来说就是多个线程的集合,它的出现主要是为了更方便的管理线程。

从结构角度看,线程组与线程之间其实是一个父子结构,一个线程组可以拥有几个线程,同时也可以拥有几个线程组。整个组织结构像一棵树一样,每个线程一定有一个线程组,线程组可能又有一个父线程组,追溯到根节点就是一个系统线程组。

线程组与线程之间的关系,可以用如下图来描述。

比如,我们通常创建的main方法,对应的是main线程,它所属的是main线程组,main线程组的父级是是system系统线程组。

public static void main(String[] args) {Thread currentThread = Thread.currentThread();ThreadGroup currentThreadGroup = currentThread.getThreadGroup();ThreadGroup systemThreadGroup = currentThreadGroup.getParent();System.out.println("currentThread:" + currentThread.getName());System.out.println("currentThreadGroup:" + currentThreadGroup.getName());System.out.println("systemThreadGroup:" + systemThreadGroup.getName());
}

输出结果如下:

currentThread:main
currentThreadGroup:main
systemThreadGroup:system

其中system线程组就是根节点,再上一层就没有了,如果调用会抛空指针异常。

线程组最主要的作用是:可以实现批量管理线程或者线程组,有效的对线程或者线程组对象进行检查、尝试中断等操作。

下面我们就一起来看看ThreadGroup的常用方法和使用技巧。

三、线程组用法详解

3.1、构造方法介绍

ThreadGroup提供了两个构造方法,内容如下:

方法描述
ThreadGroup(String name)根据线程组名称创建线程组,其父线程组为main线程组
ThreadGroup(ThreadGroup parent, String name)根据线程组名称创建线程组,其父线程组为指定的 parent 线程组

其中支持指定父级线程组的方法,在实际的使用中比较常见。

下面,我们演示一下这两个构造函数的用法:

public static void main(String[] args) {ThreadGroup subThreadGroup1 = new ThreadGroup("sub1");ThreadGroup subThreadGroup2 = new ThreadGroup(subThreadGroup1, "sub2");System.out.println("sub1 parent thread group name:" + subThreadGroup1.getParent().getName());System.out.println("sub2 parent thread group name:" + subThreadGroup2.getParent().getName());
}

输出结果如下:

sub1 parent thread group name:main
sub2 parent thread group name:sub1
3.2、核心方法介绍

ThreadGroup提供了很多有用的方法,下面整理了一些方法的简要介绍,内容如下:

方法描述
public final String getName()返回此线程组的名称
public final ThreadGroup getParent()返回此线程组的父级
public final boolean parentOf(ThreadGroup g)测试此线程组是线程组参数还是其父级线程组之一
public int activeCount()返回此线程组及其子组中活动线程的数量的估计值,递归遍历该线程组中所有的子组,此方法主要用于调试和监视目的
public int activeGroupCount ()返回此线程组及其子组中活动组的数目的估计值。递归遍历该线程组中的所有子群,此方法主要用于调试和监视目的
public final void checkAccess()确定当前运行的线程是否具有修改此线程组的权限
public int enumerate(Thread[] list)将这个线程组复制到它所在的组及其子组中
public final void destroy()销毁此线程组及其所有子组,当线程组还要子线程或者子线程组,会抛异常
public boolean isDestroyed()测试此线程组是否已被销毁
public final int getMaxPriority()返回此线程组的最大优先级
public final void setMaxPriority(int pri)设置组的最大优先级。线程组中具有较高优先级的线程不会受到影响
public final boolean isDaemon()测试此线程组是否是守护线程组
public final void setDaemon(boolean daemon)修改此线程组的守护进程状态
public final void interrupt()尝试中断此线程组中的所有线程
public void list()将此线程组的信息打印到标准输出。此方法仅用于调试

下面我们抽取几个比较常见的方法,进行演示介绍。

3.2.1、activeCount 方法

activeCount()方法用于返回此线程组及其子组中活动线程的数量的估计值,因为线程的数量是动态发生变化的,返回的值只是一个估计值。

我们看一个简单的例子就知道了。

public class MyThread extends Thread{public MyThread(ThreadGroup group, String name) {super(group, name);}@Overridepublic void run() {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}
}
public class MyThreadMainTest {public static void main(String[] args) throws Exception {ThreadGroup tg = new ThreadGroup("group1");MyThread t1 = new MyThread (tg, "t1");MyThread t2 = new MyThread (tg, "t2");t1.start();t2.start();System.out.println("线程组的名称:" +  tg.getName() + ",活动的线程数:" +  tg.activeCount());Thread.sleep(1000);System.out.println("线程组的名称:" +  tg.getName() + ",活动的线程数:" +  tg.activeCount());}
}

输出结果如下:

线程组的名称:group1,活动的线程数:2
线程组的名称:group1,活动的线程数:0

第一次检查线程都处于运行状态,因此活动的线程数为 2;过 1 秒之后,线程运行结束,活动的线程数为 0。

3.2.2、isDaemon 方法

setDaemon()方法用于测试此线程组是否是守护线程组。

需要注意的是:后台线程组和后台线程是两个概念,后台线程组的特性是最后一个线程执行完或最后一个线程被销毁时,后台线程组自动销毁,线程组只是为了统一管理线程的一个方式,跟后台线程有区别!

例子如下:

public class MyThread extends Thread{public MyThread(ThreadGroup group, String name) {super(group, name);}@Overridepublic void run() {System.out.println("当前线程:" + Thread.currentThread().getName() + ",是否后台线程:" +  Thread.currentThread().isDaemon());System.out.println("当前线程组:" + Thread.currentThread().getThreadGroup().getName() + ",是否后台线程组:" +  Thread.currentThread().getThreadGroup().isDaemon());}
}
public class MyThreadMainTest4 {public static void main(String[] args) throws Exception {ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();new MyThread(mainGroup, "t1").start();Thread.sleep(100);// 设置守护线程组ThreadGroup tg = new ThreadGroup("group1");tg.setDaemon(true);new MyThread(tg,"t2").start();}
}

输出结果如下:

当前线程:t1,是否后台线程:false
当前线程组:main,是否后台线程组:false
当前线程:t2,是否后台线程:false
当前线程组:group1,是否后台线程组:true
3.2.3、interrupt 方法

interrupt()方法用于尝试中断此线程组中的所有线程。如果正在运行的线程没有进入阻塞,是无法中断的。

例子如下:

public class MyThreadA extends Thread{public MyThreadA(ThreadGroup group, String name) {super(group, name);}@Overridepublic void run() {System.out.println("线程:" + Thread.currentThread().getName() + ",开始运行");String t;for (int i = 0; i < 1000000000; i++) {t = i + "";}System.out.println("线程:" + Thread.currentThread().getName() + ",停止运行");}
}
public class MyThreadB extends Thread{public MyThreadB(ThreadGroup group, String name) {super(group, name);}@Overridepublic void run() {System.out.println("线程:" + Thread.currentThread().getName() + ",开始运行");while (!Thread.interrupted()){}System.out.println("线程:" + Thread.currentThread().getName() + ",停止运行");}
}
public class MyThreadC extends Thread{public MyThreadC(ThreadGroup group, String name) {super(group, name);}@Overridepublic void run() {System.out.println("线程:" + Thread.currentThread().getName() + ",开始运行");try {Thread.sleep(1000);} catch (Exception e){
//            e.printStackTrace();}System.out.println("线程:" + Thread.currentThread().getName() + ",停止运行");}
}
public class MyThreadMainTest {public static void main(String[] args) throws Exception {ThreadGroup tg = new ThreadGroup("group1");new MyThreadA(tg,"t1").start();new MyThreadB(tg,"t2").start();new MyThreadC(tg,"t3").start();// 尝试中断线程组里面的线程tg.interrupt();}
}

输出结果如下:

线程:t1,开始运行
线程:t2,开始运行
线程:t2,停止运行
线程:t3,开始运行
线程:t3,停止运行

线程t1只有等它运行结束,通过interrupt()不能中断程序!

四、小结

本文主要围绕线程组的一些基本概念以及常用方法,并结合了一些简单示例进行介绍。

线程组的出现更多的是便于有组织的管理线程,比如 Java 的线程池就用到了线程组,更多的线程知识,我们在后续的文章中会进行介绍。

如果有描述不对的地方,欢迎网友留言指出。

五、参考

1、https://www.cnblogs.com/xrq730/p/4856072.html

2、https://cloud.tencent.com/developer/article/1633465

六、写到最后

最近无意间获得一份阿里大佬写的技术笔记,内容涵盖 Spring、Spring Boot/Cloud、Dubbo、JVM、集合、多线程、JPA、MyBatis、MySQL 等技术知识。需要的小伙伴可以点击如下链接获取,资源地址:技术资料笔记。

不会有人刷到这里还想白嫖吧?点赞对我真的非常重要!在线求赞。加个关注我会非常感激!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/518472.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【格与代数系统】特殊的格

【格与代数系统】偏序关系、偏序集与全序集 【格与代数系统】基本概念和性质 格与其诱导的代数系统可以看作格的两种表现形式。 目录 分配格 有界格 有补格 布尔代数 例1 例2 对偶格 软代数 完备格 稠密性 优软代数 小结 分配格 设是格&#xff0c;若其上的两个二…

【Python】新手入门(8):什么是迭代?迭代的作用是什么?

【Python】新手入门&#xff08;8&#xff09;&#xff1a;什么是迭代&#xff1f;迭代有什么应用&#xff1f; &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】…

RK809-code切换不同模式

author daisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主 daisy.skye_嵌入式,Linux,Qt-CSDN博客daisy.skye擅长嵌入式,Linux,Qt,等方面的知识https://blog.csdn.net/qq_40715266?typeblog 默认模式下放音和收音都是关闭状态 130|rk3568_r:/ # tinymix -D 1 Mixer name: ro…

云渲染平台都开始涨价了?2024年性价比高的云渲染平台推荐

最近部分云渲染平台开始涨价&#xff0c;不论是通过调整机器性能&#xff0c;还是直接提价&#xff0c;都会对成本产生影响。这对已经习惯了平台价格的用户来说&#xff0c;并不是一件好事。这里举一些例子&#xff1a; 比如平台A&#xff0c;原“首小时渲染0.66元模式”已经下…

网络信息安全:nginx漏洞收集(升级至最新版本)

网络&信息安全&#xff1a;nginx漏洞收集&#xff08;升级至最新版本&#xff09; 一、风险详情1.1 nginx 越界写入漏洞(CVE-2022-41742)1.2 nginx 缓冲区错误漏洞(CVE-2022-41741)1.3 nginx 拒绝服务漏洞&#xff08;CNVD-2018-22806&#xff09; 二、nginx升级步骤 &…

高级运维工程师手把手教从0到1搭建一套linux服务器硬盘监控平台实战训练

高级运维工程师手把手教你获取当前服务器硬盘空间数据并写入MYSQL数据库监控表实战 一、前言 我们在日常工作生活中&#xff0c;经常遇到服务器硬盘爆满的事故&#xff0c;现在互联网的监控产品非常丰富&#xff0c;但是有些场景下不得不自己解决。有些特殊条件下不能用互联网…

【vue2项目总结】——动态渲染

文章目录 主页渲染封装接口页面调用传到子组件 搜索列表渲染根据关键字搜索分类id搜索 主页渲染 封装接口 封装准备接口 api/home.js import request from /utils/request// 获取首页数据 export const getHomeData () > {return request.get(/page/detail, {params: {p…

ThreeJs场景中添加视频

这节讲如何在threejs中添加一个视频的功能&#xff0c;在某些场景中可能会需要播放视频&#xff0c;比如在场景中方式一个大屏幕&#xff0c;大屏幕上需要播放视频&#xff0c;亦或者在场景中添加电视机的模型&#xff0c;电视机的画面上需要播放一些视频等。 其实添加视频和以…

Python读取influxDB数据库

1. influxDB连接 首先用InfluxDBStudio软件连接influxDB数据库来查看所有表&#xff1a; 2. 写sql语句来查询数据 然后和平时写sql查询语句一样&#xff0c;先创建连接client&#xff0c;然后调用其query函数来查询获取数据 self.client influxdb.InfluxDBClient(hostinflu…

Vue+SpringBoot打造校园疫情防控管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学生2.2 老师2.3 学校管理部门 三、系统展示四、核心代码4.1 新增健康情况上报4.2 查询健康咨询4.3 新增离返校申请4.4 查询防疫物资4.5 查询防控宣传数据 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBoot…

制片管理工具:提高制片效率的必备工具

一、什么是制片管理工具 制片管理工具是一种为制片人提供支持和协助的软件或工具&#xff0c;并提供一种集中管理制作进度、任务分配、成本预算、资源管理和进度跟踪的方式。它可以帮助制片人在项目的开发、制作和发布方面更有效地进行规划和监督&#xff0c;确保整个流程能够…

线程安全——使用线程安全函数,多线程中执行fork引发的问题及如何解决

目录 一、引例 二、线程安全 三、多线程中执行fork 3.1 多线程中某个线程调用 fork()&#xff0c;子进程会有和父进程相同数量的线程吗? 3.2 父进程被加锁的互斥锁 fork 后在子进程中是否已经加锁 一、引例 在主线程和函数线程中进行语句分割并输出。 #include <stdi…