Java 多執行緒基礎(十一)執行緒優先順序和守護執行緒
- 2020 年 6 月 24 日
- 筆記
- Java 多執行緒基礎
Java 多執行緒基礎(十一)執行緒優先順序和守護執行緒
一、執行緒優先順序
Java 提供了一個執行緒調度器來監控程式啟動後進去就緒狀態的所有執行緒。執行緒調度器通過執行緒的優先順序來決定調度哪些執行緒執行。一般來說,Java的執行緒調度器採用時間片輪轉演算法使多個執行緒輪轉獲得CPU的時間片。然而根據實際情況,每個執行緒的重要程式也不相同,有時候我們想讓一些執行緒優先執行,那麼我們可以將他的優先順序調高一下,這樣它們獲得的時間片會多一些。
多個執行緒處於就緒狀態時,若這些執行緒的優先順序相同,則執行緒調度器會按時間片輪轉方式或獨佔方式來分配執行緒的執行時間。
java 中的執行緒優先順序的範圍是1~10,默認的優先順序是5。「高優先順序執行緒」會優先於「低優先順序執行緒」執行。
Java中執行緒優先順序分為三個級別:
- 低優先順序:1~4,其中類變數 Thread.MIN_PRORITY 最低,數值為1;
- 默認優先順序:如果一個執行緒沒有指定優先順序,默認優先順序為5,由類變數 Thread.NORM_PRORITY表示;
- 高優先順序:6~10,類變數 Thread.MAX_PRORITY 最高,數值為10。
注意:具有相同優先順序的多個執行緒,若它們都為高優先順序Thread.MAX_PRORITY,則每個執行緒都是獨佔式的,也就是這些執行緒將被順序執行;若它們優先順序不是高優先順序,則這些執行緒將被同時執行,可以說是無序執行。
java 中有兩種執行緒:用戶執行緒和守護執行緒。可以通過 isDaemon() 方法來區別它們:如果返回 false,則說明該執行緒是「用戶執行緒」;否則就是「守護執行緒」。
用戶執行緒一般用戶執行用戶級任務,而守護執行緒也就是「後台執行緒」,一般用來執行後台任務。需要注意的是:Java虛擬機在「用戶執行緒」都結束後會後退出。
JDK中對用戶執行緒與守護執行緒的解釋:
每個執行緒都有一個優先順序。「高優先順序執行緒」會優先於「低優先順序執行緒」執行。每個執行緒都可以被標記為一個守護進程或非守護進程。在一些運行的主執行緒中創建新的子執行緒時,
子執行緒的優先順序被設置為等於「創建它的主執行緒的優先順序」,當且僅當「創建它的主執行緒是守護執行緒」時「子執行緒才會是守護執行緒」。
當Java虛擬機啟動時,通常有一個單一的非守護執行緒(該執行緒通過是通過main()方法啟動)。JVM會一直運行直到下面的任意一個條件發生,JVM就會終止運行:
①、調用了exit()方法,並且exit()有許可權被正常執行。
②、所有的「非守護執行緒」都死了(即JVM中僅僅只有「守護執行緒」)。
每一個執行緒都被標記為「守護執行緒」或「用戶執行緒」。當只有守護執行緒運行時,JVM會自動退出。
二、執行緒優先順序示例
public class Demo01 { private static Object obj = new Object(); public static void main(String[] args) { Thread t1 = new ThreadA("t1"); Thread t2 = new ThreadA("t2"); t1.setPriority(1); // 設置優先順序為1 t2.setPriority(10);// 設置優先順序為10 t1.start(); t2.start(); } } class ThreadA extends Thread{ public ThreadA(String name) { super(name); } public void run() { for(int i = 0;i < 3;i++) System.out.println(Thread.currentThread().getName() + " [ " + Thread.currentThread().getPriority() + " ] loop " + i); } }
// 運行結果 t1 [ 1 ] loop 0 t2 [ 10 ] loop 0 t2 [ 10 ] loop 1 t2 [ 10 ] loop 2 t1 [ 1 ] loop 1 t1 [ 1 ] loop 2
說明:
①、主執行緒main的優先順序是5。
②、t1的優先順序被設為1,而t2的優先順序被設為10。cpu在執行t1和t2的時候,根據時間片輪循調度,所以能夠並發執行。
三、守護執行緒示例
public class Demo { public static void main(String[] args) { System.out.println(Thread.currentThread().getName() +" [ isDaemon = "+Thread.currentThread().isDaemon()+ " ]"); Thread t1=new ThreadA("t1"); Thread t2=new MyDaemon("t2"); t2.setDaemon(true);// 設置t2為守護執行緒 t1.start(); t2.start(); } } class ThreadA extends Thread{ public ThreadA(String name) { super(name); } public void run(){ try { for (int i=0; i<5; i++) { Thread.sleep(3); System.out.println(this.getName() +"[ isDaemon = "+this.isDaemon()+ " ] " + "loop " + i); } } catch (InterruptedException e) { } } }; class MyDaemon extends Thread{ public MyDaemon(String name) { super(name); } public void run(){ try { for (int i=0; i<10000; i++) { Thread.sleep(1); System.out.println(this.getName() +"[ isDaemon = " + this.isDaemon() + " ] " +"loop "+i); } } catch (InterruptedException e) { } } }
// 運行結果 main [ isDaemon = false ] t2[ isDaemon = true ] loop 0 t2[ isDaemon = true ] loop 1 t2[ isDaemon = true ] loop 2 t1[ isDaemon = false ] loop 0 t2[ isDaemon = true ] loop 3 t2[ isDaemon = true ] loop 4 t1[ isDaemon = false ] loop 1 t2[ isDaemon = true ] loop 5 t2[ isDaemon = true ] loop 6 t2[ isDaemon = true ] loop 7 t1[ isDaemon = false ] loop 2 t2[ isDaemon = true ] loop 8 t2[ isDaemon = true ] loop 9 t2[ isDaemon = true ] loop 10 t1[ isDaemon = false ] loop 3 t2[ isDaemon = true ] loop 11 t2[ isDaemon = true ] loop 12 t2[ isDaemon = true ] loop 13 t2[ isDaemon = true ] loop 14 t1[ isDaemon = false ] loop 4 t2[ isDaemon = true ] loop 15
說明:
①、主執行緒main是用戶執行緒,它創建的子執行緒t1也是用戶執行緒。
②、t2 是守護執行緒。在「主執行緒main」和「子執行緒t1」(它們都是用戶執行緒)執行完畢,只剩t2這個守護執行緒的時候,JVM自動退出。