java併發(一)wait,notify的使用

Java是第一個內置對多線程支持的主流編程語言。在Java5以前,對多線程的支持主要是經過對塊結構的同步實現的(synchronized配合wait,notify,notifyAll),Java5引入了java.util.concurrent包,提供了對多線程編程的更高層的支持。 java

在Java中,除了int等基本類型以外,一切皆爲對象。synchronized關鍵字以及Object類中的wait,notify和notifyAll方法爲咱們編寫多線程程序提供了原始的支持。 算法

例如: 編程


public class A {
	public synchronized void fun() {
		...
	}
}

在調用方法fun以前,調用該方法的執行線程必需要先得到類A的實例(a)的對象鎖。上面的方法fun在功能上等同於: 多線程

public void fun() {
	synchronized(this) {
		...
	}
}
在執行fun以前,要獲取a的對象鎖,在方法fun返回以前,要釋放a的對象鎖。

一般可使用synchronized和notify,notifyAll以及wait方法來實現線程之間的數據傳遞及控制。對於對象obj來講: 編程語言

  • obj.wait():該方法的調用,使得調用該方法的執行線程(T1)放棄obj的對象鎖並阻塞,直到別的線程調用了obj的notifyAll方法、或者別的線程調用了obj的notify方法且JVM選擇喚醒(T1),被喚醒的線程(T1)依舊阻塞在wait方法中,與其它的線程一塊兒爭奪obj的對象鎖,直到它再次得到了obj的對象鎖以後,才能從wait方法中返回。(除了notify方法,wait還有帶有時間參數的版本,在等待了超過所設時間以後,T1線程同樣會被喚醒,進入到爭奪obj對象鎖的行列;另外中斷能夠直接跳出wait方法)
  • obj.notify():該方法的調用,會從全部正在等待obj對象鎖的線程中,喚醒其中的一個(選擇算法依賴於不一樣實現),被喚醒的線程此時加入到了obj對象鎖的爭奪之中,然而該notify方法的執行線程此時並未釋放obj的對象鎖,而是離開synchronized代碼塊時釋放。所以在notify方法以後,synchronized代碼塊結束以前,全部其餘被喚醒的,等待obj對象鎖的線程依舊被阻塞。
  • obj.notifyAll():與notify的區別是,該方法會喚醒全部正在等待obj對象鎖的線程。(不過同一時刻,也只有一個線程能夠擁有obj的對象鎖)

要注意的是,wai,notify以及notifyAll方法的調用必須在相應的synchronized代碼塊之中。例如: ide


synchronized(obj) {
	while(xxx) {
		obj.wait();
	}
	...
}

下面寫個小例子,來講明wait方法返回以前要從新得到對象鎖,以及notify方法執行以後並不當即釋放對象鎖。 this

public class MThread implements Runnable {
	public synchronized void assign() {
		this.notifyAll();
		System.err.println("out of notifyAll");
		while(true){}
	}
	
	public synchronized void await() throws InterruptedException {
		this.wait(5000);
		System.err.println("out of wait");
	}

	@Override
	public void run() {
			try {
				await();
			} catch (InterruptedException e) {
			}
	}

}


public class Main {
	public static void main(String[] args) {
		MThread mThread = new MThread();
		Thread thread = new Thread(mThread);
		thread.start();
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		mThread.assign();
	}
}
主線程中,先建立子線程,並啓動,主線程sleep一秒鐘是爲了讓子線程中的this.wait(5000)獲得執行,而wait(5000)又保證在五秒鐘結束以前,主線程中的mThread.assign()方法獲得調用,進而調用子線程的notifyAll方法,來喚醒wait方法。從執行結果中能夠看到「out of notifyAll」的輸出,卻始終看不到「out of wait」,這說明notifyAll方法執行完成,而wait方法並未返回。一個合理的解釋就是wait還在等待mThread的對象鎖,而notifyAll執行完成後也並未當即釋放mThread的對象鎖,sun的官方文檔的說明也是如此。

十點半了,哎,第一次發博客,不知如何,有點小忐忑 spa

相關文章
相關標籤/搜索