1. 程式人生 > >多執行緒等待喚醒機制

多執行緒等待喚醒機制

示例程式碼取自傳智播客畢向東老師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三十多天,對於程式設計知識所知太少,分享只為交流個人理解,僅供參考,難免有錯。希望有大神如果發現我理解中的錯誤,一定指出來!

對了,上面應該是等待,不是休眠!!