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向對應,只是提供了一些統一的管理操作的方法。
-
String getName():返回此線程組的名稱。
-
ThreadGroup getParent():返回此線程組的父級。
-
boolean parentOf(ThreadGroup g):測試此線程組是否是其祖先線程組之一。
-
void interrupt():中斷此線程組中的所有線程。
-
void setMaxPriority(int pri):設置組的最大優先級。
-
int getMaxPriority():返回此線程組的最大優先級。
-
void setDaemon(boolean daemon):更改此線程組的守護程序狀態。守護線程組最后一個線程停止或最后一個線程組被銷毀時自動銷毀。
-
boolean isDaemon():測試此線程組是否是守護線程組。
-
void destroy():銷毀此線程組及其所有子組, 此線程組必須為空,表示此線程組中的所有線程已停止。如果線程組不為空或線程組已被破壞,則拋出"IllegalThreadStateException"。
-
boolean isDestroyed():測試此線程組是否已被破壞。
-
int activeCount():返回此線程組及其子組中活動線程數的估計。
-
int activeGroupCount():返回此線程組及其子組中活動組數的估計。
-
void checkAccess():確定當前運行的線程是否有權限修改此線程組。在ThreadGroup中涉及任意線程、線程組的操作都需要對這些線程線程組的權限進行檢查,若無權限都會拋出“SecurityException”。
-
int enumerate(Thread[] list):將此線程組及其子組中的每個活動線程復制到指定的數組中。相當於enumerate(Thread[] list, true)
-
int enumerate(Thread[] list, boolean recurse):若recurse為true,遞歸將此線程組中的每個活動線程復制到指定的數組中。
-
int enumerate(ThreadGroup[] list):復制到該線程組及其子組中每個活動子組的指定數組引用。
-
int enumerate(ThreadGroup[] list, boolean recurse):復制到該線程組中每個活動子組的指定數組引用。
-
void list():將有關此線程組的信息打印到標准輸出。
-
String toString():返回此Thread組的字符串表示形式。
-
void uncaughtException(Thread t, Throwable e):當此線程組中的線程因為一個未捕獲的異常由Java Virtual Machine調用,而線程不具有特定Thread.UncaughtExceptionHandler安裝。
-
void resume():已棄用,這種方法僅與Thread.suspend和ThreadGroup.suspend一起使用 ,這兩種方法都已經被棄用,因為它們本身就是死鎖的。 詳見Thread.suspend() 。
-
void stop():已棄用,這種方法本質上是不安全的。 詳見Thread.stop() 。
-
void suspend():已棄用,這種方法本質上是死鎖的。 詳見Thread.suspend() 。
-
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 參考
0、JAVA多線程編程
Java多線程編程所涉及的知識點包含線程創建、線程同步、線程間通信、線程死鎖、線程控制(掛起、停止和恢復)。之前
-
篇0
-
篇1
-
篇2
-
篇3
-
篇4
-
篇5
-
篇6
-
篇7
-
篇8