對於不少初學 Java 線程的小夥伴們,很容易將 Thread 類裏的 yield() 方法理解錯誤,或者理解得不夠透徹,先看下源碼:多線程
public static native void yield();
是的,你沒看錯,Thread 類源碼中定義的這個方法沒有方法體,native 關鍵字修飾的方法表示原生態方法,方法對應的實現不在這個類文件裏,而是在用其餘語言(如 C 和 C++)實現的文件中。Java 語言自己不能對操做系統底層進行訪問和操做(但能夠經過 JNI 接口調用其餘語言來實現對底層的訪問)。因此,想要知道並理解 yield() 方法的具體實現過程,於初學者來講並無必要。雖然「無代碼無真相」,但採用大白話的解釋或許更加通俗易懂吧。函數
在各類各樣的線程中,Java 虛擬機必須實現一個有優先權的、基於優先級的調度程序。這意味着 Java 程序中的每個線程被分配到必定的優先權,使用定義好的範圍內的一個正整數表示。優先級能夠被開發者改變。即便線程已經運行了必定時間,Java 虛擬機也不會改變其優先級。學習
優先級的值很重要,由於 Java 虛擬機和下層的操做系統之間的約定是操做系統必須選擇有最高優先權的 Java 線程運行。因此咱們說 Java 實現了一個基於優先權的調度程序。該調度程序使用一種有優先權的方式實現,這意味着當一個有更高優先權的線程到來時,不管低優先級的線程是否在運行,都會中斷(搶佔)它。這個約定對於操做系統來講並不老是這樣,這意味着操做系統有時可能會選擇運行一個更低優先級的線程。spa
接下來,理解線程優先級是多線程學習很重要的一步,尤爲是瞭解 yield() 函數的工做過程:操作系統
一、記住當線程的優先級沒有指定時,全部線程都攜帶普通優先級。
二、優先級能夠用從 1 到 10 的範圍指定。10 表示最高優先級,1 表示最低優先級,5 是普通優先級。
三、記住優先級最高的線程在執行時被給予優先。可是不能保證線程在啓動時就進入運行狀態。
四、與在線程池中等待運行機會的線程相比,當前正在運行的線程可能老是擁有更高的優先級。
五、由調度程序決定哪個線程被執行。
六、t.setPriority() 用來設定線程的優先級。
七、記住在線程 start() 方法被調用以前,線程的優先級應該被設定。
八、你可使用常量,如 MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORITY 來設定優先級。線程
如今,咱們對線程調度和線程優先級有必定理解了,進入主題。翻譯
Thread.yield() 方法會使當前線程從執行狀態(運行狀態)變爲可執行狀態(就緒狀態)。CPU 會從衆多的可執行態裏選擇,也就是說,當前也就是剛剛調用 yield() 方法的那個線程仍是有可能會被再次繼續執行的。yield() 方法並非讓當前線程暫停,讓出時間片去執行其餘線程,而在下一次時間片內就必定不會執行了(當前線程只是轉換爲就緒狀態,在下一個本該是本身的卻讓給其餘線程的時間片內也可能再次繼續被執行)。code
不少人將 yield 翻譯成線程讓步。顧名思義,就是說當一個線程使用了這個方法以後,它就會把本身CPU執行的一段時間片讓給本身或者其它的線程運行。接口
看以下例子:開發
public class TestYield { public static void main(String[] args) { MyThread3 t1 = new MyThread3("t1"); MyThread3 t2 = new MyThread3("t2"); t1.start(); t2.start(); } } class MyThread3 extends Thread { MyThread3(String s) { super(s); } public void run() { for (int i = 1; i <= 100; i++) { System.out.println(getName() + ": " + i); if (i % 10 == 0) { yield(); } } } }
再看運行結果:
. . . t1: 8 t1: 9 t1: 10 t2: 6 t1: 11 . . . t1: 18 t1: 19 t1: 20 t1: 21 t1: 22 . . .
t1: 10 後 t2: 6;t1: 20 後 t1: 21。
總結後可得如下重要的幾點:
一、yield 是一個靜態的原生(native)方法。 二、yield 告訴當前正在執行的線程把運行機會交給線程池中擁有相同優先級的線程。 三、yield 不能保證使得當前正在運行的線程迅速轉換到可運行的狀態。 四、它僅能使一個線程從運行狀態轉到可運行狀態,而不是等待或阻塞狀態。