在之前的多線程系列文章中,我們陸陸續續的介紹了Thread線程類相關的知識和用法,其實在Thread類上還有一層ThreadGroup類,也就是線程組。 ...
一、簡介
在之前的多線程系列文章中,我們陸陸續續的介紹了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);
}
@Override
public 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);
}
@Override
public 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);
}
@Override
public 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);
}
@Override
public 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);
}
@Override
public 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
作者:程式員志哥
出處:pzblog.cn
資源:微信搜【程式員志哥】關註我,回覆 【技術資料】有我準備的一線程式必備電腦書籍、大廠面試資料和免費電子書。 希望可以幫助大家提升技術和能力。