多執行緒等待喚醒機制
阿新 • • 發佈:2018-11-19
示例程式碼取自傳智播客畢向東老師25天Java基礎教程,添加了一些觀測列印程式碼,便於理解分析。對於程序分析理解純粹個人理解,剛學Java沒多久,難免有錯,僅供參考,如果大神們發現錯誤,希望能幫忙指出,也幫我走出錯誤的理解。
先貼程式碼
class Res{ String name; String sex; boolean flag=false; } class Input implements Runnable{ private Res r; public Input(Res r) { this.r=r; } public void run() { int k=0; int a=0;//設定執行緒中有限次迴圈引數,便於觀測執行資料 while (a<5) { //設定迴圈5次 synchronized(r) {//設定同一鎖 if(r.flag) try { System.out.println("設定引數休眠");//用於觀測本執行緒是否進入休眠 r.wait(); } catch (Exception e) {} if(k==0) { r.name="Mike"; r.sex="man"; System.out.println("wozai mikezheli");//用於觀測本是否進行此處成員變數賦值 }else { r.name="麗麗"; r.sex="女女女女女女"; System.out.println("我在 麗麗這裡");//用於觀測本是否進行此處成員變數賦值 } a++; k=(k+1)%2; r.flag=true; r.notify(); } } } } class Output implements Runnable{ private Res r; Output(Res r){ this.r=r; } public void run() { int b=0; while (b<5) { synchronized(r) { if(!r.flag) try { System.out.println("列印引數休眠*****");//用於觀測本執行緒是否進入休眠 r.wait(); } catch (Exception e) {} System.out.println(Thread.currentThread().getName()+r.name+"------"+r.sex); b++; r.flag=false; r.notify(); } } } } public class InOutput { public static void main(String[] args) { Res r=new Res(); Input in=new Input(r); Output out=new Output(r); Thread t1=new Thread(in); Thread t2=new Thread(out); t1.start(); t2.start(); } }
執行結果:1、
wozai mikezheli
列印輸出執行緒b Mike------man
列印引數休眠*****
我在 麗麗這裡
列印輸出執行緒b 麗麗------女女女女女女
列印引數休眠*****
wozai mikezheli
列印輸出執行緒b Mike------man
列印引數休眠*****
我在 麗麗這裡
列印輸出執行緒b 麗麗------女女女女女女
列印引數休眠*****
wozai mikezheli
列印輸出執行緒b Mike------man
這是出現最多的一種結果。首先賦值執行緒a啟動,進入while迴圈,經同步鎖進入同步程式碼塊中,if(r.flag)判定,執行緒a未進入等待,直接進行if(k==0)判定,分別賦值Mike和man,此時和輸出我們設定的觀測語句“wozai mikezheli”,執行完接下來的語句且喚醒執行緒b,結束同步程式碼塊。注意:此時執行緒a與b都是就緒狀態,都可執行!!由結果可知,執行緒a再次搶奪到執行資質(NB啊),經同步鎖進入同步程式碼塊中,if(r.flag)判定,執行緒a進入等待(白搶了),同時放棄已佔有的同步鎖資源。執行緒b經同步鎖進入同步程式碼塊,經if(!r.flag)判斷,執行緒b未進行等待。執行程式碼輸出語句“列印輸出執行緒b Mike------man”,執行完接下來的語句且喚醒執行緒a,結束同步程式碼塊。此時a與b又都進入到就緒狀態,搶奪執行權。由結果知b搶到了,但由於判斷條件的引數改變,只能去等待,a執行賦值後喚醒b,結束同步程式碼塊。再次競爭。。。。不管哪次競爭結果如何,如果剛執行完的執行緒搶到,由於引數設定的改變,都只能進入等待,對外表現為兩執行緒交替執行。如果倆執行緒都處於就緒狀態,競爭應該一直存在,未必只發生在倆執行緒都在同步程式碼塊外面的時候,只不過,某一執行緒即使爭到了也進不去同步鎖或只能進入等待。以上分析大概率是錯的,對於程式設計知道的太少了,只是現階段的個人理解。
還有一種比較特別的結果(執行很多次會出現):
列印引數執行緒b休眠*****
wozai mikezheli
列印輸出執行緒b Mike------man
列印引數執行緒b休眠*****
我在 麗麗這裡
設定引數執行緒a休眠
列印輸出執行緒b 麗麗------女女女女女女
列印引數執行緒b休眠*****
wozai mikezheli
設定引數執行緒a休眠
列印輸出執行緒b Mike------man
列印引數執行緒b休眠*****
我在 麗麗這裡
設定引數執行緒a休眠
列印輸出執行緒b 麗麗------女女女女女女
列印引數執行緒b休眠*****
wozai mikezheli
列印輸出執行緒b Mike------man
雖然執行緒a在主執行緒中先啟動,執行緒b後啟動,但是在第一次的競爭中還是輸了,唉。。
學習Java三十多天,對於程式設計知識所知太少,分享只為交流個人理解,僅供參考,難免有錯。希望有大神如果發現我理解中的錯誤,一定指出來!
對了,上面應該是等待,不是休眠!!