1. 程式人生 > >Java執行緒Thread之yeild方法解析

Java執行緒Thread之yeild方法解析

轉載請標明出處:
http://blog.csdn.net/hesong1120/article/details/79032252
本文出自:hesong的專欄

Java執行緒Thread的yeild方法可能在日常使用中比較少出現,那它是做什麼用的,我們先查查官方文件解釋。

yield
public static void yield()
Causes the currently executing thread object to temporarily pause and allow other threads to execute.

看原版官方文件可以避免出現歧義,我的理解是

造成當前正在執行的執行緒物件臨時性的暫停,和允許其他執行緒去執行

也就是說,呼叫了yield方法之後,當前執行緒會臨時性的暫停一下,然後其他執行緒有機會去執行任務。那麼實際情況是怎麼樣,我們用例子來測試一下。

public class YieldTest{

  private static final int DEST_NUM = 50;

  public static void main(String[] args) {
    new YieldTest();
  }

  public YieldTest(){

    ThreadDemo yt1 = new ThreadDemo("張三"
); ThreadDemo yt2 = new ThreadDemo("李四"); ThreadDemo yt3 = new ThreadDemo("王五"); //yt1.setPriority(10); //yt1.setPriority(5); //yt3.setPriority(1); yt1.start(); yt2.start(); yt3.start(); } public class ThreadDemo extends Thread{ public ThreadDemo(String name){ setName(name); } @Override
public void run() { for (int i = 1; i <= DEST_NUM; i++) { // 當i為30時,該執行緒就會把CPU時間讓掉,讓其他或者自己的執行緒執行(也就是誰先搶到誰執行) if (i % 5 == 0) { System.out.println("" + this.getName() + "-----" + i + " yeild一下"); yield(); }else{ System.out.println("" + this.getName() + "-----" + i); } } } } }

上面的例子是,開啟張三,李四,王五三個執行緒分別列印從1到50的數字,每當列印的數字是5的倍數時(比如列印5,10,15等),就yield一下。那麼我們看看執行之後的結果是怎麼樣的。

張三-----1
王五-----1
李四-----1
王五-----2
王五-----3
王五-----4
張三-----2
張三-----3
王五-----5    yeild一下
李四-----2
李四-----3
李四-----4
李四-----5    yeild一下      /////////
李四-----6
李四-----7
李四-----8
王五-----6
王五-----7
王五-----8
王五-----9
王五-----10    yeild一下
張三-----4
張三-----5    yeild一下     //////////
張三-----6
張三-----7
張三-----8
張三-----9
張三-----10    yeild一下    /////////
張三-----11
張三-----12
張三-----13
張三-----14
張三-----15    yeild一下    /////////
張三-----16
張三-----17
張三-----18
張三-----19

//其餘的省略
。。。

可以看到這次張三雖然多次yeild了,但是依然繼續執行了。我們再執行一次看看

張三-----1
張三-----2
張三-----3
張三-----4
張三-----5    yeild一下
李四-----1
李四-----2
李四-----3
李四-----4
李四-----5    yeild一下
王五-----1
王五-----2
王五-----3
王五-----4
王五-----5    yeild一下
張三-----6
張三-----7
張三-----8
張三-----9
張三-----10    yeild一下
李四-----6
李四-----7
李四-----8
李四-----9
李四-----10    yeild一下
王五-----6
王五-----7
王五-----8
王五-----9
王五-----10    yeild一下
張三-----11
張三-----12
張三-----13
張三-----14
張三-----15    yeild一下
李四-----11
李四-----12
李四-----13
李四-----14
李四-----15    yeild一下
王五-----11
王五-----12
王五-----13
王五-----14
王五-----15    yeild一下
張三-----16
張三-----17
張三-----18
張三-----19
張三-----20    yeild一下
李四-----16
李四-----17

//其餘的省略
。。。

yield原理

發現這一次,每次呼叫了yeild之後,它們都沒有緊接著執行了。這是為什麼呢,難道yield沒有用處了嗎?
其實上面出現的不確定結果,是因為多核CPU執行的關係,一個執行緒呼叫了yield方法之後,確實會讓出當前使用的CPU,讓自己從【執行態】變為【就緒態】。
- 當執行環境是單核CPU的時候。如果其他執行緒已經處於就緒態,正在等待CPU時間片時,這時有執行緒yield讓出了CPU時間片,它們中的一個就會先有可能分配到CPU時間片,進而進入【執行態】,執行執行緒內容。
- 而當執行環境是多核CPU的話。也許上面的三個執行緒都是同時處於【執行態】正在執行,那個一個執行緒yiedl之後,短暫的讓出了它的CPU,而此時又沒有執行緒跟它搶CPU(因為其他兩個都在執行著),所以它可能又獲得了CPU時間片又去執行了。所以針對多核CPU環境的話,測試結果並沒有明顯的規律。

yield錯誤觀點糾正

網上有說“yield之後,只有同優先順序的執行緒能執行,低優先順序的執行緒無法獲得執行”,這是錯誤的觀點,Java文件並沒有這種說,Java虛擬機器也並沒有這種限制。會大概率出現這種情況主要是因為yield之後,高優先順序的執行緒會更容易得到排程優先得到CPU時間片執行,低優先順序自然被執行的概率就更少了,但是並不是說低優先順序執行緒就無法被執行。可以把上面程式碼的優先順序設定部分註釋去掉,自己親自執行看看結果,別被誤導了。

yield的使用場景

yield的作用就是暫時讓出使用著的CPU,這樣其他【就緒態】的執行緒就有機會佔用這個CPU去執行。所以yield的使用場景多在,當前執行緒在進行耗時性的操作時(如IO操作),並且因為它的優先順序較高,導致一些優先順序較低的執行緒被分配的時間片更少,這樣優先順序低的執行緒就要等待更長時間才能完成操作,那麼這時適當地呼叫幾次yield方法讓出CPU,讓優先順序低的執行緒多得到執行,這樣才能高效的實現程式執行和響應。

我的部落格
GitHub
我的簡書
群號:194118438,歡迎入群
微信公眾號 hesong ,微信掃一掃下方二維碼即可關注: