線程組(ThreadGroup)
在一個系統中,如果線程數量很多,而且功能分配比較明確,就可以將相同功能的線程放置在同一個線程組裏。下面通過示例來說明。
public class ThreadGroupName implements Runnable {
public static void main(String[] args){
ThreadGroup tg = new ThreadGroup("PringGroup");
Thread t1 = new Thread(tg, new ThreadGroupName(), "T1");
Thread t2 = new Thread(tg, new ThreadGroupName(), "T2");
t1.start();
t2.start();
System.out.println(tg.activeCount());
tg.list();
}
@Override
public void run(){
String groupAndName = Thread.currentThread().getThreadGroup().getName() + "-" + Thread.currentThread().getName();
while (true) {
System.out.println("I am " + groupAndName);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
上述代碼中,第4行建立了一個名爲“PrintGroup”的線程組,並將T1和T2兩個線程加入到此線程組中。第5、6兩行創建了兩個線程,使用Thread的構造函數,指定了線程所屬的線程組,將線程和線程組關聯起來。activeCount()方法可以獲得活動線程的總數。不過線程是動態的,因此這個值只是一個估計值,無法精確。list()方法打印這個線程組中所有的線程信息,對調試有一定幫助。打印結果如下:
線程組還有一個值得注意的方法stop(),它會停止線程組中所有的線程。看起來是一個很方便的方法,但它會遇到和Thread.stop()方法同樣的問題,因此使用時需要格外謹慎。
另外,提一下編碼習慣。在創建線程和線程組的時候,建議取一個好聽名字。對計算機來說不重要,但在系統出現問題時,很可能需要知道系統內的所有線程,如果拿到的是一連串的Thread-0、Thread-1、Thread-2,一定會頭疼。而如果看到的是類似HttpHandler、FTPService這樣的名字,則會順心很多。
守護線程(Daemon)
守護線程是一種特殊的線程,就像它的名字一樣,它是系統的守護者。在後臺默默的完成一些系統性的服務,比如垃圾回收線程、JIT線程就可以理解爲守護線程。與之相應的是用戶線程,用戶線程可以認爲是系統的工作線程,它會完成這個程序應該要完成的業務操作。如果用戶線程全部結束,則意味着這個程序實際上無事可做了。守護線程要守護的對象已經不存在了,那麼整個應用程序就應該結束。因此一個Java應用內只有守護線程時,Java虛擬機就會自然退出。
下面看一個簡單的守護線程的應用。
public class DaemonDemo {
public static void main(String[] args) throws InterruptedException {
Thread t = new DaemonT();
// 將線程t設置爲守護線程,注意這一步要在start()方法之前設置
t.setDaemon(true);
t.start();
Thread.sleep(2000);
}
public static class DaemonT extends Thread{
@Override
public void run(){
while (true){
System.out.println("I am alive");
try {
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
}
上述代碼中,第6行將線程t設置爲守護線程。需要注意的是,設置守護線程必須在start()方法之前設置。否則出拋出下面的異常,告訴你守護線程設置失敗。不過程序和線程依然可以正常執行,從打印的結果中也看到了,還是打印了“I am alive”。只不過被當作用戶線程而已。因此如果不小心忽略了下面的異常信息,很可能察覺不到這個錯誤,就會詫異爲什麼程序永遠停不下來呢?
在這個例子中,由於線程t被設置爲守護線程,系統中只有主線程main爲用戶線程,因此在main線程休眠2秒鐘後退出時,整個程序也隨之結束了。但如果不把線程t設置爲守護線程,那main線程結束後,t線程還會不停地打印,永遠也不會結束。正確的結果打印如下:
注:以上內容參考《實戰Java高併發程序設計(第2版)》。