類似于在計算機中使用文件夾管理文件,也可以使用線程組來管理線程,在線程組中定義一組相似(相關)的線程,在線程組中也可以定義子線程組。
Thread類有幾個構造方法允許在創建線程時指定線程組,如果在創建線程時沒有指定線程組則該線程就屬于父線程所在的線程組,JVM在創建main線程時會為它指定一個線程組,因此每個Java線程都有一個線程組與之關聯, 可以調用線程的getThreadGroup()方法返回線程組。
線程組開始是出于安全的考慮設計用來區分不同的Applet,然而ThreadGroup并未實現這一目標,在新開發的系統中,已經不常用線程組,現在一般會將一組相關的線程存入一個數組或一個集合中,如果僅僅是用來區分線程時,可以使用線程名稱來區分,多數情況下,可以忽略線程組。
package com.wkcto.threadgroup;
/**
* 演示創建線程組
*/
public class Test01 {
public static void main(String[] args) {
// 1) 返回當前main線程的線程組
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
System.out.println(mainGroup);
//2) 定義線程組,如果不指定所屬線程組,則自動歸屬當前線程所屬的線程組中
ThreadGroup group1 = new ThreadGroup("group1");
System.out.println(group1);
//3)定義線程組, 同時指定父線程組
ThreadGroup group2 = new ThreadGroup(mainGroup, "group2");
//現在group1與group2都是maingroup線程組中的子線程組, 調用線程組的getParent()方法返回父線程組
System.out.println( group1.getParent() == mainGroup); //true
System.out.println( group2.getParent() == mainGroup);
//4) 在創建線程時指定所屬線程組
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread());
}
};
//在創建線程時,如果沒有指定線程組,則默認線程歸屬到父線程的線程組中
//在main線程中創建了t1線程,稱main線程為父線程,t1線程為子線程, t1沒有指定線程組則t1線程就歸屬到父線程main線程的線程組中
Thread t1 = new Thread(r, "t1");
System.out.println( t1 ); //Thread[t1,5,main], t1的線程組是main線程組
//創建線程時,可以指定線程所屬線程組
Thread t2 = new Thread(group1, r, "t2");
Thread t3 = new Thread(group2, r, "t3");
System.out.println(t2);
System.out.println(t3);
}
}
Java線程組的基本操作
activeCount() 返回當前線程組及子線程組中活動線程的數量(近似值)。
activeGroupCount() 返回當前線程組及子線程組中活動線程組的數量(近似值)。
int enumerate(Thread[] list) 將當前線程組中的活動線程復制到參數數組中。
enumerate(ThreadGroup[] list) 將當前線程組中的活動線程組復制到參數數組中。
getMaxPriority() 返回線程組的最大優先級,默認是10。
getName() 返回線程組的名稱。
getParent() 返回父線程組。
interrupt() 中斷線程組中所有的線程。
isDaemon() 判斷當前線程組是否為守護線程組。
list() 將當前線程組中的活動線程打印出來。
parentOf(ThreadGroup g) 判斷當前線程組是否為參數線程組的父線程組。
setDaemon(boolean daemon) 設置線程組為守護線程組。
package com.wkcto.threadgroup;
/**
* 演示線程組的基本操作
*/
public class Test02 {
public static void main(String[] args) {
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup(); //返回當前線程組
//再定義線程組
ThreadGroup group = new ThreadGroup("group"); //默認group的父線程組是main線程組
Runnable r = new Runnable() {
@Override
public void run() {
while (true){
System.out.println("-----------當前線程: " + Thread.currentThread());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t1 = new Thread(r, "t1"); //默認在main線程組中創建線程
Thread t2 = new Thread(group, r, "t2"); //在指定的group線程組中創建線程
t1.start();
t2.start();
//打印線程組的相關屬性
System.out.println("main 線程組中活動線程數量: " + mainGroup.activeCount()); //4, main線程組中活動線程: main, t1, t2, 垃圾回收器
System.out.println("group 子線程組中活動線程數量: " + group.activeCount()); //1, t2
System.out.println("main線程組中子線程組數量: " + mainGroup.activeGroupCount()); //1, group
System.out.println("group子線程組中子線程組數量: " + group.activeGroupCount()); //0
System.out.println("main線程組的父線程組: " + mainGroup.getParent()); //main線程組的父線程組是system
System.out.println("group線程組的父線程組: " + group.getParent()); //main
System.out.println( mainGroup.parentOf(mainGroup)); //true, 線程組也是它自己的父線程組
System.out.println( mainGroup.parentOf(group)); //true
mainGroup.list(); //把main線程組中所有的線程打印輸出
}
}
復制線程組中的線程及子線程組
enumerate(Thread[] list) 把當前線程組和子線程組中所有的線程復制到參數數組中。
enumerate(Thread[] list, boolean recursive) , 如果第二個參數設置為false,則只復制當前線程組中所有的線程,不復制子線程組中的線程。
enumerate(ThreadGroup[] list) 把當前線程組和子線程組中所有的線程組復制到參數數組中。
enumerate(ThreadGroup[] list, boolean recurse) 第二個參數設置false,則只復制當前線程組的子線程組。
package com.wkcto.threadgroup;
/**
* 演示復制線程組中的內容
*/
public class Test03 {
public static void main(String[] args) {
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup(); //返回main線程的main線程組
//main線程組中定義了兩個子線程組
ThreadGroup group1 = new ThreadGroup("group1"); //默認group1的父線程組就是當前線程組main
ThreadGroup group2 = new ThreadGroup(mainGroup, "group2");
Runnable r = new Runnable() {
@Override
public void run() {
while (true){
System.out.println("----當前線程: " + Thread.currentThread());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
//創建并啟動三個線程
Thread t1 = new Thread(r, "t1"); //默認在main線程組中創建線程
Thread t2 = new Thread(group1, r, "t2"); //在group1線程組中創建線程
Thread t3 = new Thread(group2, r, "t3"); //在group2線程組中創建線程
t1.start();
t2.start();
t3.start();
//1) 把main線程組中的線程復制到數組中
//先定義存儲線程的數組,數組的長度為main線程組中活動線程的數量
Thread[] threadList = new Thread[mainGroup.activeCount()];
/* //把main線程組包括子線程組中的所有的線程復制到數組中
mainGroup.enumerate(threadList);
//遍歷threadList數組
for (Thread thread : threadList) {
System.out.println(thread);
}
System.out.println("----------------------------");*/
//只把main線程組中的線程復制到數組中,不包含子線程組的線程
mainGroup.enumerate(threadList, false);
//遍歷threadList數組
for (Thread thread : threadList) {
System.out.println(thread);
}
System.out.println("----------------------------");
//2) 把main線程組中的子線程組復制到數組中
//定義數組存儲線程組
ThreadGroup [] threadGroups = new ThreadGroup[mainGroup.activeGroupCount()];
//把main線程組中的子線程組復制到數組中
mainGroup.enumerate(threadGroups);
System.out.println("============================");
for (ThreadGroup threadGroup : threadGroups) {
System.out.println(threadGroup);
}
}
}
線程組的批量中斷
線程組的interrupt() 可以給該線程組中所有的活動線程添加中斷標志。
package com.wkcto.threadgroup;
/**
* 線程組的批量中斷
*/
public class Test04 {
public static void main(String[] args) throws InterruptedException {
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("當前線程--" + Thread.currentThread() + "--開始循環");
//當線程沒有被中斷就一直循環
while ( !Thread.currentThread().isInterrupted()){
System.out.println(Thread.currentThread().getName() + "------------------");
/* try {
Thread.sleep(500);
} catch (InterruptedException e) {
//如果中斷睡眠中的線程,產生中斷異常, 同時會清除中斷標志
e.printStackTrace();
}*/
}
System.out.println(Thread.currentThread().getName() + "循環結束");
}
};
//創建線程組
ThreadGroup group = new ThreadGroup("group");
//在group線程組中創建5個線程
for (int i = 0; i < 5; i++) {
new Thread(group,r).start();
}
//main線程睡眠2秒
Thread.sleep(50);
//中斷線程組, 會中斷線程組中所有的線程
group.interrupt();
}
}
設置守護線程組
守護線程是為其他線程提供服務的,當JVM中只有守護線程時,守護線程會自動銷毀,JVM會退出。
調用線程組的setDaemon(true)可以把線程組設置為守護線程組,當守護線程組中沒有任何活動線程時,守護線程組會自動銷毀。
注意線程組的守護屬性,不影響線程組中線程的守護屬性,或者說守護線程組中的線程可以是非守護線程。
package com.wkcto.threadgroup;
/**
* 演示設置守護線程組
*/
public class Test05 {
public static void main(String[] args) throws InterruptedException {
//先定義線程組
ThreadGroup group = new ThreadGroup("group");
//設置線程組為守護線程組
group.setDaemon(true);
//向組中添加3個線程
for (int i = 0; i < 3; i++) {
new Thread(group, new Runnable() {
@Override
public void run() {
for (int j = 0; j < 20; j++) {
System.out.println(Thread.currentThread().getName() + " -- " + j);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
//main線程睡眠5秒
Thread.sleep(5000);
System.out.println("main...end....");
}
}