Java線程可以有優先級的設定,高優先級的線程比低優先級的線程有更高的幾率得到執行(不完全正確,請參考下面的“線程優先級的問題“)。
- 記住當線程的優先級沒有指定時,所有線程都攜帶普通優先級。
- 優先級可以用從1到10的范圍指定。10表示最高優先級,1表示最低優先級,5是普通優先級。
- 記住優先級最高的線程在執行時被給予優先。但是不能保證線程在啟動時就進入運行狀態。
- 與在線程池中等待運行機會的線程相比,當前正在運行的線程可能總是擁有更高的優先級。
- 由調度程序決定哪一個線程被執行。
- t.setPriority()用來設定線程的優先級。
- 記住在線程開始方法被調用之前,線程的優先級應該被設定。
- 你可以使用常量,如MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORITY來設定優先級。
優先級的取值
Java線程的優先級是一個整數,其取值范圍是1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。
Thread源代碼里對NORM_PRIORITY (數值為5) 的注釋是“線程默認的優先級”
其實不然。默認的優先級是父線程的優先級。在init方法里,
Thread parent = currentThread(); this.priority = parent.getPriority();
或許這么解釋是因為Java程序的主線程(main方法)的優先級默認是為NORM_PRIORITY,這樣不主動設定優先級的,后續創建的線程的優先級也都是NORM_PRIORITY了。
public static void main(String[] args) { System.out.println(Thread.currentThread().getPriority()); }
其執行結果是5。
設置優先級
可以通過setPriority方法(final的,不能被子類重載)更改優先級。優先級不能超出1-10的取值范圍,否則拋出IllegalArgumentException。另外如果該線程已經屬於一個線程組(ThreadGroup),該線程的優先級不能超過該線程組的優先級:
其中setPriority0是一個本地方法。
private native void setPriority0(int i);
線程組的最大優先級
我們可以設定線程組的最大優先級,當創建屬於該線程組的線程時該線程的優先級不能超過這個數。
線程組最大優先級的設定:
- 系統線程組的最大優先級默認為Thread.MAX_PRIORITY
- 創建線程組的時候其最大優先級默認為父線程組(如果未指定父線程組,則其父線程組默認為當前線程所屬線程組)的最大優先級
- 可以通過setMaxPriority更改最大優先級,但無法超過父線程組的最大優先級
setMaxPriority的問題:
- 該方法只能更改本線程組及其子線程組(遞歸)的最大優先級。
- 但不能影響已經創建的直接或間接屬於該線程組的線程的優先級,也就是說,即使目前有一個子線程的優先級比新設定的線程組優先級大,也不會更改該子線程的優先級。只有當試圖改變子線程的優先級或者創建新的子線程的時候,線程組的最大優先級才起作用。
線程優先級的問題
對於線程優先級,我們需要注意:
* Thread.setPriority()可能根本不做任何事情,這跟你的操作系統和虛擬機版本有關
* 線程優先級對於不同的線程調度器可能有不同的含義,可能並不是你直觀的推測。特別地,優先級並不一定是指CPU的分享。在UNIX系統,優先級或多或少可以認為是CPU的分配,但Windows不是這樣
* 線程的優先級通常是全局的和局部的優先級設定的組合。Java的setPriority()方法只應用於局部的優先級。換句話說,你不能在整個可能的范圍 內設定優先級。(這通常是一種保護的方式,你大概不希望鼠標指針的線程或者處理音頻數據的線程被其它隨機的用戶線程所搶占)
* 不同的系統有不同的線程優先級的取值范圍,但是Java定義了10個級別(1-10)。這樣就有可能出現幾個線程在一個操作系統里有不同的優先級,在另外一個操作系統里卻有相同的優先級(並因此可能有意想不到的行為)
* 操作系統可能(並通常這么做)根據線程的優先級給線程添加一些專有的行為(例如”only give a quantum boost if the priority is below X“)。這里再重復一次,優先級的定義有部分在不同系統間有差別。
* 大多數操作系統的線程調度器實際上執行的是在戰略的角度上對線程的優先級做臨時操作(例如當一個線程接收到它所等待的一個事件或者I/O),通常操作系統知道最多,試圖手工控制優先級可能只會干擾這個系統。
* 你的應用程序通常不知道有哪些其它進程運行的線程,所以對於整個系統來說,變更一個線程的優先級所帶來的影響是難於預測的。例如你可能發現,你有一個預期 為偶爾在后台運行的低優先級的線程幾乎沒有運行,原因是一個病毒監控程序在一個稍微高一點的優先級(但仍然低於普通的優先級)上運行,並且無法預計你程序 的性能,它會根據你的客戶使用的防病毒程序不同而不同。
* Thread.setPriority()可能根本不做任何事情,這跟你的操作系統和虛擬機版本有關
* 線程優先級對於不同的線程調度器可能有不同的含義,可能並不是你直觀的推測。特別地,優先級並不一定是指CPU的分享。在UNIX系統,優先級或多或少可以認為是CPU的分配,但Windows不是這樣
* 線程的優先級通常是全局的和局部的優先級設定的組合。Java的setPriority()方法只應用於局部的優先級。換句話說,你不能在整個可能的范圍 內設定優先級。(這通常是一種保護的方式,你大概不希望鼠標指針的線程或者處理音頻數據的線程被其它隨機的用戶線程所搶占)
* 不同的系統有不同的線程優先級的取值范圍,但是Java定義了10個級別(1-10)。這樣就有可能出現幾個線程在一個操作系統里有不同的優先級,在另外一個操作系統里卻有相同的優先級(並因此可能有意想不到的行為)
* 操作系統可能(並通常這么做)根據線程的優先級給線程添加一些專有的行為(例如”only give a quantum boost if the priority is below X“)。這里再重復一次,優先級的定義有部分在不同系統間有差別。
* 大多數操作系統的線程調度器實際上執行的是在戰略的角度上對線程的優先級做臨時操作(例如當一個線程接收到它所等待的一個事件或者I/O),通常操作系統知道最多,試圖手工控制優先級可能只會干擾這個系統。
* 你的應用程序通常不知道有哪些其它進程運行的線程,所以對於整個系統來說,變更一個線程的優先級所帶來的影響是難於預測的。例如你可能發現,你有一個預期 為偶爾在后台運行的低優先級的線程幾乎沒有運行,原因是一個病毒監控程序在一個稍微高一點的優先級(但仍然低於普通的優先級)上運行,並且無法預計你程序 的性能,它會根據你的客戶使用的防病毒程序不同而不同。
實際編碼注意事項
- 不要假定高優先級的線程一定先於低優先級的線程執行,不要有邏輯依賴於線程優先級,否則可能產生意外結果