Java充电社
专辑
博文
联系我
本人继续续收门徒,亲手指导
Java高并发教程
-> 线程组
1、必须知道的几个概念
2、并发级别
3、有关并行的两个重要定律
4、JMM相关的一些概念
5、深入理解进程和线程
6、线程的基本操作
7、volatile与Java内存模型
8、线程组
9、用户线程和守护线程
10、线程安全和synchronized
11、中断线程的几种方式
12、JUC中ReentrantLock
13、JUC中的Condition
14、JUC中的LockSupport工具类
15、UC中的Semaphore(信号量)
16、JUC中的CountDownLatch
17、JUC中的循环栅栏CyclicBarrier
18、线程池
19、JUC中的Executor框架详解1
20、JUC中的Executor框架详解2
21、java中的CAS
22、java中的UnSafe类
23、JUC中的原子操作类
24、ThreadLocal、InheritableThreadLocal
25、JUC中的阻塞队列
26、JUC中一些常见的集合
27、实战:你的接口太慢了需要优化
28、实战:构建日志系统
29、实战:一起来搞懂限流
30、JUC中的CompletableFuture
31、等待线程完成的方式你知道几种?
32、原子操作增强类LongAdder、LongAccumulator
33、怎么演示公平锁和非公平锁
34、谷歌提供的一些好用的并发工具类
35、延迟队列 DelayQueue 详解
36、线程6种状态详解
37、如何实现一个通用的延迟队列?
上一篇:volatile与Java内存模型
下一篇:用户线程和守护线程
<div style="display:none"></div> ## 线程组 我们可以把线程归属到某个线程组中,线程组可以包含多个**线程**以及**线程组**,线程和线程组组成了父子关系,是个树形结构,如下图: ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/8/f68f70d6-9d03-460c-8bea-2fcec7cc2f29.png) 使用线程组可以方便管理线程,线程组提供了一些方法方便方便我们管理线程。 ## 创建线程关联线程组 创建线程的时候,可以给线程指定一个线程组,代码如下: ```java package com.itsoku.chat02; import java.util.concurrent.TimeUnit; /** * <b>description</b>: <br> * <b>time</b>:2019/7/13 17:53 <br> * <b>author</b>:微信公众号:路人甲Java,专注于java技术分享(带你玩转 爬虫、分布式事务、异步消息服务、任务调度、分库分表、大数据等),喜欢请关注! */ public class Demo1 { public static class R1 implements Runnable { @Override public void run() { System.out.println("threadName:" + Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) throws InterruptedException { ThreadGroup threadGroup = new ThreadGroup("thread-group-1"); Thread t1 = new Thread(threadGroup, new R1(), "t1"); Thread t2 = new Thread(threadGroup, new R1(), "t2"); t1.start(); t2.start(); TimeUnit.SECONDS.sleep(1); System.out.println("活动线程数:" + threadGroup.activeCount()); System.out.println("活动线程组:" + threadGroup.activeGroupCount()); System.out.println("线程组名称:" + threadGroup.getName()); } } ``` 输出结果: ```txt threadName:t1 threadName:t2 活动线程数:2 活动线程组:0 线程组名称:thread-group-1 ``` **activeCount()**方法可以返回线程组中的所有活动线程数,包含下面的所有子孙节点的线程,由于线程组中的线程是动态变化的,这个值只能是一个估算值。 ## 为线程组指定父线程组 创建线程组的时候,可以给其指定一个父线程组,也可以不指定,如果不指定父线程组,则父线程组为当前线程的线程组,java api有2个常用的构造方法用来创建线程组: ```java public ThreadGroup(String name) public ThreadGroup(ThreadGroup parent, String name) ``` 第一个构造方法未指定父线程组,看一下内部的实现: ```java public ThreadGroup(String name) { this(Thread.currentThread().getThreadGroup(), name); } ``` 系统自动获取当前线程的线程组作为默认父线程组。 上一段示例代码: ```java package com.itsoku.chat02; import java.util.concurrent.TimeUnit; /** * <b>description</b>: <br> * <b>time</b>:2019/7/13 17:53 <br> * <b>author</b>:微信公众号:路人甲Java,专注于java技术分享(带你玩转 爬虫、分布式事务、异步消息服务、任务调度、分库分表、大数据等),喜欢请关注! */ public class Demo2 { public static class R1 implements Runnable { @Override public void run() { Thread thread = Thread.currentThread(); System.out.println("所属线程组:" + thread.getThreadGroup().getName() + ",线程名称:" + thread.getName()); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) throws InterruptedException { ThreadGroup threadGroup1 = new ThreadGroup("thread-group-1"); Thread t1 = new Thread(threadGroup1, new R1(), "t1"); Thread t2 = new Thread(threadGroup1, new R1(), "t2"); t1.start(); t2.start(); TimeUnit.SECONDS.sleep(1); System.out.println("threadGroup1活动线程数:" + threadGroup1.activeCount()); System.out.println("threadGroup1活动线程组:" + threadGroup1.activeGroupCount()); System.out.println("threadGroup1线程组名称:" + threadGroup1.getName()); System.out.println("threadGroup1父线程组名称:" + threadGroup1.getParent().getName()); System.out.println("----------------------"); ThreadGroup threadGroup2 = new ThreadGroup(threadGroup1, "thread-group-2"); Thread t3 = new Thread(threadGroup2, new R1(), "t3"); Thread t4 = new Thread(threadGroup2, new R1(), "t4"); t3.start(); t4.start(); TimeUnit.SECONDS.sleep(1); System.out.println("threadGroup2活动线程数:" + threadGroup2.activeCount()); System.out.println("threadGroup2活动线程组:" + threadGroup2.activeGroupCount()); System.out.println("threadGroup2线程组名称:" + threadGroup2.getName()); System.out.println("threadGroup2父线程组名称:" + threadGroup2.getParent().getName()); System.out.println("----------------------"); System.out.println("threadGroup1活动线程数:" + threadGroup1.activeCount()); System.out.println("threadGroup1活动线程组:" + threadGroup1.activeGroupCount()); System.out.println("----------------------"); threadGroup1.list(); } } ``` 输出结果: ```txt 所属线程组:thread-group-1,线程名称:t1 所属线程组:thread-group-1,线程名称:t2 threadGroup1活动线程数:2 threadGroup1活动线程组:0 threadGroup1线程组名称:thread-group-1 threadGroup1父线程组名称:main ---------------------- 所属线程组:thread-group-2,线程名称:t4 所属线程组:thread-group-2,线程名称:t3 threadGroup2活动线程数:2 threadGroup2活动线程组:0 threadGroup2线程组名称:thread-group-2 threadGroup2父线程组名称:thread-group-1 ---------------------- threadGroup1活动线程数:4 threadGroup1活动线程组:1 ---------------------- java.lang.ThreadGroup[name=thread-group-1,maxpri=10] Thread[t1,5,thread-group-1] Thread[t2,5,thread-group-1] java.lang.ThreadGroup[name=thread-group-2,maxpri=10] Thread[t3,5,thread-group-2] Thread[t4,5,thread-group-2] ``` 代码解释: 1. **threadGroup1未指定父线程组,系统获取了主线程的线程组作为threadGroup1的父线程组,输出结果中是:main** 2. **threadGroup1为threadGroup2的父线程组** 3. **threadGroup1活动线程数为4,包含了threadGroup1线程组中的t1、t2,以及子线程组threadGroup2中的t3、t4** 4. **线程组的list()方法,将线程组中的所有子孙节点信息输出到控制台,用于调试使用** ## 根线程组 获取根线程组 ```java package com.itsoku.chat02; /** * <b>description</b>: <br> * <b>time</b>:2019/7/13 17:53 <br> * <b>author</b>:微信公众号:路人甲Java,专注于java技术分享(带你玩转 爬虫、分布式事务、异步消息服务、任务调度、分库分表、大数据等),喜欢请关注! */ public class Demo3 { public static void main(String[] args) { System.out.println(Thread.currentThread()); System.out.println(Thread.currentThread().getThreadGroup()); System.out.println(Thread.currentThread().getThreadGroup().getParent()); System.out.println(Thread.currentThread().getThreadGroup().getParent().getParent()); } } ``` 运行上面代码,输出: ```java Thread[main,5,main] java.lang.ThreadGroup[name=main,maxpri=10] java.lang.ThreadGroup[name=system,maxpri=10] null ``` 从上面代码可以看出: 1. **主线程的线程组为main** 2. **根线程组为system** 看一下ThreadGroup的源码: ```java private ThreadGroup() { // called from C code this.name = "system"; this.maxPriority = Thread.MAX_PRIORITY; this.parent = null; } ``` 发现ThreadGroup默认构造方法是private的,是由c调用的,创建的正是system线程组。 ## 批量停止线程 调用线程组**interrupt()**,会将线程组树下的所有子孙线程中断标志置为true,可以用来批量中断线程。 示例代码: ```java package com.itsoku.chat02; import java.util.concurrent.TimeUnit; /** * <b>description</b>: <br> * <b>time</b>:2019/7/13 17:53 <br> * <b>author</b>:微信公众号:路人甲Java,专注于java技术分享(带你玩转 爬虫、分布式事务、异步消息服务、任务调度、分库分表、大数据等),喜欢请关注! */ public class Demo4 { public static class R1 implements Runnable { @Override public void run() { Thread thread = Thread.currentThread(); System.out.println("所属线程组:" + thread.getThreadGroup().getName() + ",线程名称:" + thread.getName()); while (!thread.isInterrupted()) { ; } System.out.println("线程:" + thread.getName() + "停止了!"); } } public static void main(String[] args) throws InterruptedException { ThreadGroup threadGroup1 = new ThreadGroup("thread-group-1"); Thread t1 = new Thread(threadGroup1, new R1(), "t1"); Thread t2 = new Thread(threadGroup1, new R1(), "t2"); t1.start(); t2.start(); ThreadGroup threadGroup2 = new ThreadGroup(threadGroup1, "thread-group-2"); Thread t3 = new Thread(threadGroup2, new R1(), "t3"); Thread t4 = new Thread(threadGroup2, new R1(), "t4"); t3.start(); t4.start(); TimeUnit.SECONDS.sleep(1); System.out.println("-----------threadGroup1信息-----------"); threadGroup1.list(); System.out.println("----------------------"); System.out.println("停止线程组:" + threadGroup1.getName() + "中的所有子孙线程"); threadGroup1.interrupt(); TimeUnit.SECONDS.sleep(2); System.out.println("----------threadGroup1停止后,输出信息------------"); threadGroup1.list(); } } ``` 输出: ```txt 所属线程组:thread-group-1,线程名称:t1 所属线程组:thread-group-1,线程名称:t2 所属线程组:thread-group-2,线程名称:t3 所属线程组:thread-group-2,线程名称:t4 -----------threadGroup1信息----------- java.lang.ThreadGroup[name=thread-group-1,maxpri=10] Thread[t1,5,thread-group-1] Thread[t2,5,thread-group-1] java.lang.ThreadGroup[name=thread-group-2,maxpri=10] Thread[t3,5,thread-group-2] Thread[t4,5,thread-group-2] ---------------------- 停止线程组:thread-group-1中的所有子孙线程 线程:t4停止了! 线程:t2停止了! 线程:t1停止了! 线程:t3停止了! ----------threadGroup1停止后,输出信息------------ java.lang.ThreadGroup[name=thread-group-1,maxpri=10] java.lang.ThreadGroup[name=thread-group-2,maxpri=10] ``` 停止线程之后,通过**list()**方法可以看出输出的信息中不包含已结束的线程了。 多说几句,建议大家再创建线程或者线程组的时候,给他们取一个有意义的名字,对于计算机来说,可能名字并不重要,但是在系统出问题的时候,你可能会去查看线程堆栈信息,如果你看到的都是t1、t2、t3,估计自己也比较崩溃,如果看到的是httpAccpHandler、dubboHandler类似的名字,应该会好很多。 ## 更多好文章 1. <a href="http://mp.weixin.qq.com/mp/homepage?__biz=MzA5MTkxMDQ4MQ==&hid=6&sn=06cb2a601f4dec19d0b34d015c107b2d&scene=25#wechat_redirect" target="_blank">spring高手系列(正在连载中)</a> 2. <a href="https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648933285&idx=1&sn=f5507c251b84c3405f2fe0f7fb1da97d&chksm=88621b9bbf15928dd4c26f52b2abb0e130cde02100c432f33f0e90123b5e4b20d43017c1030e&token=1916804008&lang=zh_CN&scene=21#wechat_redirect" target="_blank">Java高并发系列(共34篇)</a> 3. <a href="https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648933461&idx=1&sn=67cd31469273b68a258d963e53b56325&chksm=88621c6bbf15957d7308d81cd8ba1761b356222f4c6df75723aee99c265bd94cc869faba291c&token=1916804008&lang=zh_CN&scene=21#wechat_redirect" target="_blank">MySql高手系列(共27篇)</a> 4. <a href="https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648933753&idx=1&sn=0b41083939980be87a61c4f573792459&chksm=88621d47bf1594516092b662c545abfac299d296e232bf25e9f50be97e002e2698ea78218828&scene=21#wechat_redirect" target="_blank">Maven高手系列(共10篇)</a> 5. <a href="https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648933868&idx=1&sn=ed16ef4afcbfcb3423a261422ff6934e&chksm=88621dd2bf1594c4baa21b7adc47456e5f535c3358cd11ddafb1c80742864bb19d7ccc62756c&token=1400407286&lang=zh_CN#rd" target="_blank">Mybatis系列(共12篇)</a> 6. <a href="https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648933452&idx=1&sn=48b3b1cbd27c50186122fef8943eca5f&chksm=88621c72bf159564e629ee77d180424274ae9effd8a7c2997f853135b28f3401970793d8098d&token=1919005508&lang=zh_CN#rd" target="_blank">聊聊db和缓存一致性常见的实现方式</a> 7. <a href="https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648933334&idx=1&sn=3a68da36e4e21b7339418e40ab9b6064&chksm=88621be8bf1592fe5301aab732fbed8d1747475f4221da341350e0cc9935225d41bf79375d43&token=1919005508&lang=zh_CN#rd" target="_blank">接口幂等性这么重要,它是什么?怎么实现?</a> 8. <a href="https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648933878&idx=1&sn=bebd543c39d02455456680ff12e3934b&chksm=88621dc8bf1594de6b50a760e4141b80da76442ba38fb93a91a3d18ecf85e7eee368f2c159d3&token=799820369&lang=zh_CN#rd" target="_blank">泛型,有点难度,会让很多人懵逼,那是因为你没有看这篇文章!</a> ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/8/09f2f304-289e-4536-b416-8c80cbcea489.png) <a style="display:none" target="_blank" href="https://mp.weixin.qq.com/s/_S1DD2JADnXvpexxaBwLLg" style="color:red; font-size:20px; font-weight:bold">继续收门徒,亲手带,月薪 4W 以下的可以来找我</a> ## 最新资料 1. <a href="https://mp.weixin.qq.com/s?__biz=MzkzOTI3Nzc0Mg==&mid=2247484964&idx=2&sn=c81bce2f26015ee0f9632ddc6c67df03&scene=21#wechat_redirect" target="_blank">尚硅谷 Java 学科全套教程(总 207.77GB)</a> 2. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484192&idx=1&sn=505f2faaa4cc911f553850667749bcbb&scene=21#wechat_redirect" target="_blank">2021 最新版 Java 微服务学习线路图 + 视频</a> 3. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484573&idx=1&sn=7f3d83892186c16c57bc0b99f03f1ffd&scene=21#wechat_redirect" target="_blank">阿里技术大佬整理的《Spring 学习笔记.pdf》</a> 4. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484544&idx=2&sn=c1dfe907cfaa5b9ae8e66fc247ccbe84&scene=21#wechat_redirect" target="_blank">阿里大佬的《MySQL 学习笔记高清.pdf》</a> 5. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247485167&idx=1&sn=48d75c8e93e748235a3547f34921dfb7&scene=21#wechat_redirect" target="_blank">2021 版 java 高并发常见面试题汇总.pdf</a> 6. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247485664&idx=1&sn=435f9f515a8f881642820d7790ad20ce&scene=21#wechat_redirect" target="_blank">Idea 快捷键大全.pdf</a> ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/1/2883e86e-3eff-404a-8943-0066e5e2b454.png)
#custom-toc-container