所有線程都隸屬于一個線程組。那可以是一個默認線程組,亦可是一個創建線程時明確指定的組。在創建之初,線程被限制到一個組里,而且不能改變到一個不同的組。每個應用都至少有一個線程從屬于系統線程組。若創建多個線程而不指定一個組,它們就會自動歸屬于系統線程組。 線程組也必須從屬于其他線程組。必須在構建器里指定新線程組從屬于哪個線程組。若在創建一個線程組的時候沒有指定它的歸屬,則同樣會自動成為系統線程組的一名屬下。因此,一個應用程序中的所有線程組最終都會將系統線程組作為自己的“父”。 之所以要提出“線程組”的概念,很難從字面上找到原因。這多少為我們討論的主題帶來了一些混亂。一般地說,我們認為是由于“安全”或者“保密”方面的理由才使用線程組的。根據Arnold和Gosling的說法:“線程組中的線程可以修改組內的其他線程,包括那些位于分層結構最深處的。一個線程不能修改位于自己所在組或者下屬組之外的任何線程”(注釋①)。然而,我們很難判定“修改”在這兒的具體含義是什么。下面這個例子展示了位于一個“葉子組”內的線程能修改它所在線程組樹的所有線程的優先級,同時還能為這個“樹”內的所有線程都調用一個方法。 ①:《The javaPRogramming Language》第179頁。該書由Arnold和Jams Gosling編著,Addison-Wesley于1996年出版 //: Testaccess.java // How threads can access other threads // in a parent thread group public class TestAccess { public static void main(String[] args) { ThreadGroup x = new ThreadGroup("x"), y = new ThreadGroup(x, "y"), z = new ThreadGroup(y, "z"); Thread one = new TestThread1(x, "one"), two = new TestThread2(z, "two"); } } class TestThread1 extends Thread { private int i; TestThread1(ThreadGroup g, String name) { super(g, name); } void f() { i++; // modify this thread System.out.println(getName() + " f()"); } } class TestThread2 extends TestThread1 { TestThread2(ThreadGroup g, String name) { super(g, name); start(); } public void run() { ThreadGroup g = getThreadGroup().getParent().getParent(); g.list(); Thread[] gAll = new Thread[g.activeCount()]; g.enumerate(gAll); for(int i = 0; i < gAll.length; i++) { gAll[i].setPriority(Thread.MIN_PRIORITY); ((TestThread1)gAll[i]).f(); } g.list(); } } ///:~ 在main()中,我們創建了幾個ThreadGroup(線程組),每個都位于不同的“葉”上:x沒有參數,只有它的名字(一個String),所以會自動進入“system”(系統)線程組;y位于x下方,而z位于y下方。注重初始化是按照文字順序進行的,所以代碼合法。 有兩個線程創建之后進入了不同的線程組。其中,TestThread1沒有一個run()方法,但有一個f(),用于通知線程以及打印出一些東西,以便我們知道它已被調用。而TestThread2屬于TestThread1的一個子類,它的run()非常詳盡,要做許多事情。首先,它獲得當前線程所在的線程組,然后利用getParent()在繼續樹中向上移動兩級(這樣做是有道理的,因為我想把TestThread2在分級結構中向下移動兩級)。隨后,我們調用方法activeCount(),查詢這個線程組以及所有子線程組內有多少個線程,從而創建由指向Thread的句柄構成的一個數組。enumerate()方法將指向所有這些線程的句柄置入數組gAll里。然后在整個數組里遍歷,為每個線程都調用f()方法,同時修改優先級。這樣一來,位于一個“葉子”線程組里的線程就修改了位于父線程組的線程。 調試方法list()打印出與一個線程組有關的所有信息,把它們作為標準輸出。在我們對線程組的行為進行調查的時候,這樣做是相當有好處的。下面是程序的輸出: java.lang.ThreadGroup[name=x,maXPri=10] Thread[one,5,x] java.lang.ThreadGroup[name=y,maxpri=10] java.lang.ThreadGroup[name=z,maxpri=10] Thread[two,5,z] one f() two f() java.lang.ThreadGroup[name=x,maxpri=10] Thread[one,1,x] java.lang.ThreadGroup[name=y,maxpri=10] java.lang.ThreadGroup[name=z,maxpri=10] Thread[two,1,z] list()不僅打印出ThreadGroup或者Thread的類名,也打印出了線程組的名字以及它的最高優先級。