java高并發(fā)之線程組詳解
線程組
我們可以把線程歸屬到某個(gè)線程組中,線程組可以包含多個(gè)線程以及線程組,線程和線程組組成了父子關(guān)系,是個(gè)樹形結(jié)構(gòu),如下圖:

使用線程組可以方便管理線程,線程組提供了一些方法方便方便我們管理線程。
創(chuàng)建線程關(guān)聯(lián)線程組
創(chuàng)建線程的時(shí)候,可以給線程指定一個(gè)線程組,代碼如下:
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>:微信公眾號(hào):路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請關(guān)注!
*/
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("活動(dòng)線程數(shù):" + threadGroup.activeCount());
System.out.println("活動(dòng)線程組:" + threadGroup.activeGroupCount());
System.out.println("線程組名稱:" + threadGroup.getName());
}
}
輸出結(jié)果:
threadName:t1
threadName:t2
活動(dòng)線程數(shù):2
活動(dòng)線程組:0
線程組名稱:thread-group-1
activeCount()方法可以返回線程組中的所有活動(dòng)線程數(shù),包含下面的所有子孫節(jié)點(diǎn)的線程,由于線程組中的線程是動(dòng)態(tài)變化的,這個(gè)值只能是一個(gè)估算值。
為線程組指定父線程組
創(chuàng)建線程組的時(shí)候,可以給其指定一個(gè)父線程組,也可以不指定,如果不指定父線程組,則父線程組為當(dāng)前線程的線程組,java api有2個(gè)常用的構(gòu)造方法用來創(chuàng)建線程組:
public ThreadGroup(String name) public ThreadGroup(ThreadGroup parent, String name)
第一個(gè)構(gòu)造方法未指定父線程組,看一下內(nèi)部的實(shí)現(xiàn):
public ThreadGroup(String name) {
this(Thread.currentThread().getThreadGroup(), name);
}
系統(tǒng)自動(dòng)獲取當(dāng)前線程的線程組作為默認(rèn)父線程組。
上一段示例代碼:
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>:微信公眾號(hào):路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請關(guān)注!
*/
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活動(dòng)線程數(shù):" + threadGroup1.activeCount());
System.out.println("threadGroup1活動(dòng)線程組:" + 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活動(dòng)線程數(shù):" + threadGroup2.activeCount());
System.out.println("threadGroup2活動(dòng)線程組:" + threadGroup2.activeGroupCount());
System.out.println("threadGroup2線程組名稱:" + threadGroup2.getName());
System.out.println("threadGroup2父線程組名稱:" + threadGroup2.getParent().getName());
System.out.println("----------------------");
System.out.println("threadGroup1活動(dòng)線程數(shù):" + threadGroup1.activeCount());
System.out.println("threadGroup1活動(dòng)線程組:" + threadGroup1.activeGroupCount());
System.out.println("----------------------");
threadGroup1.list();
}
}
輸出結(jié)果:
所屬線程組:thread-group-1,線程名稱:t1
所屬線程組:thread-group-1,線程名稱:t2
threadGroup1活動(dòng)線程數(shù):2
threadGroup1活動(dòng)線程組:0
threadGroup1線程組名稱:thread-group-1
threadGroup1父線程組名稱:main
----------------------
所屬線程組:thread-group-2,線程名稱:t4
所屬線程組:thread-group-2,線程名稱:t3
threadGroup2活動(dòng)線程數(shù):2
threadGroup2活動(dòng)線程組:0
threadGroup2線程組名稱:thread-group-2
threadGroup2父線程組名稱:thread-group-1
----------------------
threadGroup1活動(dòng)線程數(shù):4
threadGroup1活動(dòng)線程組: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未指定父線程組,系統(tǒng)獲取了主線程的線程組作為threadGroup1的父線程組,輸出結(jié)果中是:main
2.threadGroup1為threadGroup2的父線程組
3.threadGroup1活動(dòng)線程數(shù)為4,包含了threadGroup1線程組中的t1、t2,以及子線程組threadGroup2中的t3、t4
4.線程組的list()方法,將線程組中的所有子孫節(jié)點(diǎn)信息輸出到控制臺(tái),用于調(diào)試使用
根線程組
獲取根線程組
package com.itsoku.chat02;
/**
* <b>description</b>:<br>
* <b>time</b>:2019/7/13 17:53 <br>
* <b>author</b>:微信公眾號(hào):路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請關(guān)注!
*/
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());
}
}
運(yùn)行上面代碼,輸出:
Thread[main,5,main]
java.lang.ThreadGroup[name=main,maxpri=10]
java.lang.ThreadGroup[name=system,maxpri=10]
null
從上面代碼可以看出:
1.主線程的線程組為main
2.根線程組為system
看一下ThreadGroup的源碼:
private ThreadGroup() { // called from C code
this.name = "system";
this.maxPriority = Thread.MAX_PRIORITY;
this.parent = null;
}
發(fā)現(xiàn)ThreadGroup默認(rèn)構(gòu)造方法是private的,是由c調(diào)用的,創(chuàng)建的正是system線程組。
批量停止線程
調(diào)用線程組interrupt(),會(huì)將線程組樹下的所有子孫線程中斷標(biāo)志置為true,可以用來批量中斷線程。
示例代碼:
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>:微信公眾號(hào):路人甲Java,專注于java技術(shù)分享(帶你玩轉(zhuǎn) 爬蟲、分布式事務(wù)、異步消息服務(wù)、任務(wù)調(diào)度、分庫分表、大數(shù)據(jù)等),喜歡請關(guān)注!
*/
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();
}
}
輸出:
所屬線程組: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()方法可以看出輸出的信息中不包含已結(jié)束的線程了。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
安卓系統(tǒng)中實(shí)現(xiàn)搖一搖畫面振動(dòng)效果的方法
這篇文章主要介紹了安卓系統(tǒng)中實(shí)現(xiàn)搖一搖畫面振動(dòng)效果的方法,調(diào)用Android SDK中的SensorEventListener接口,需要的朋友可以參考下2015-07-07
IntelliJ IDEA Java項(xiàng)目手動(dòng)添加依賴 jar 包的方法(圖解)
這篇文章主要介紹了IntelliJ IDEA Java項(xiàng)目手動(dòng)添加依賴 jar 包,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
SpringBoot自動(dòng)配置Quartz的實(shí)現(xiàn)步驟
本文主要介紹了SpringBoot自動(dòng)配置Quartz的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
淺談hashmap為什么查詢時(shí)間復(fù)雜度為O(1)
這篇文章主要介紹了hashmap為什么查詢時(shí)間復(fù)雜度為O(1),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
Java8新特性之StampedLock_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
本文從synchronized、Lock到Java8新增的StampedLock進(jìn)行對比分析,對Java8新特性之StampedLock相關(guān)知識(shí)感興趣的朋友一起看看吧2017-06-06
JavaWEB項(xiàng)目之如何配置動(dòng)態(tài)數(shù)據(jù)源
這篇文章主要介紹了JavaWEB項(xiàng)目之如何配置動(dòng)態(tài)數(shù)據(jù)源問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
使用@SpringBootTest注解進(jìn)行單元測試
這篇文章主要介紹了使用@SpringBootTest注解進(jìn)行單元測試,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
如何利用Spring把元素解析成BeanDefinition對象
這篇文章主要介紹了如何利用Spring把元素解析成BeanDefinition對象,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08

