1. 程式人生 > >《Java並發編程的藝術》讀書筆記:等待/通知機制

《Java並發編程的藝術》讀書筆記:等待/通知機制

package tex 藝術 pri new [] 返回 ati block

看這本書之前,對wait和notify認識大概就是,調用wait的線程A堵塞之後,一旦另外有線程調用notify方法。線程A會立馬從wait方法處返回。看完這本書後。發現自己的認識實在太膚淺了。。。。。

線程調用wait()後,會釋放已經獲得的鎖。

同一時候進入Waiting狀態,而非Blocked狀態。唯獨等待其它的線程調用notify()方法且釋放鎖之後。當前線程才會從wait()方法處返回。只發出通知是不夠用的。還須要發出通知的線程釋放鎖。

然而notify()方法的調用並不意味著鎖的釋放。

貼出原書的demo,稍作了些改動。

/**
 *
 */
package chapter04;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 6-11
 */
public class WaitNotify {
	private static final SimpleDateFormat sdf  = new SimpleDateFormat("HH:mm:ss");
	static               boolean          flag = true;
	static               Object           lock = new Object();

	public static void main(String[] args) {
		Thread waitThread = new Thread(new Wait(), "WaitThread");
		waitThread.start();
		sleepSeconds(1);

		Thread notifyThread = new Thread(new Notify(), "NotifyThread");
		notifyThread.start();
	}

	static class Wait implements Runnable {
		public void run() {
			synchronized (lock) {
				// 當條件不滿足時,繼續wait,同一時候釋放了lock的鎖
				while (flag) {
					try {
						System.out.println(CuttentThreadName() + " flag is true. wait @ " + sdf.format(new Date()));
						lock.wait();
						System.out.println(CuttentThreadName() + " gained lock again. wait @ " + sdf.format(new Date()));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				// 條件滿足時。完畢工作
				System.out.println(CuttentThreadName() + " flag is false. running @ " + sdf.format(new Date()));
			}
		}
	}

	private static String CuttentThreadName() {
		return Thread.currentThread().getName();
	}

	static class Notify implements Runnable {
		@Override
		public void run() {
			// 加鎖,擁有lock的Monitor
			synchronized (lock) {
				// 獲取lock的鎖。然後進行通知,通知時不會釋放lock的鎖,
				// 直到當前線程釋放了lock後,WaitThread才幹從wait方法中返回
				System.out.println(CuttentThreadName() + " hold lock. notify @ " + sdf.format(new Date()));
				lock.notifyAll();
				flag = false;
				sleepSeconds(5);
				System.out.println(CuttentThreadName() + " is releasing lock  @ " + sdf.format(new Date()));
			}
			// 再次加鎖
			synchronized (lock) {
				System.out.println(CuttentThreadName() + " hold lock again. sleep @ " + sdf.format(new Date()));
				sleepSeconds(5);
				System.out.println(CuttentThreadName() + " is releasing lock  @ " + sdf.format(new Date()));
			}
		}
	}

	private static void sleepSeconds(int timeout) {
		try {
			TimeUnit.SECONDS.sleep(timeout);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

輸出結果為:

WaitThread flag is true. wait @ 20:58:32
NotifyThread hold lock. notify @ 20:58:33
NotifyThread is releasing lock  @ 20:58:38
NotifyThread hold lock again. sleep @ 20:58:38
NotifyThread is releasing lock  @ 20:58:43
WaitThread gained lock again. wait @ 20:58:43
WaitThread flag is false. running @ 20:58:43

通過輸出結果,我們能夠發現幾個問題。

1.NotifyThread調用notifyAll()方法後,WaitThread並沒有立馬從wait()方法處返回。

由於這個時候NotifyThread並沒有釋放鎖。

2.程序61行,NotifyThread第一次釋放鎖,然而WaitThread不爭氣,並沒有搶到這把鎖。依然處於Blocked狀態。

3.直到67行。NotifyThread再一次釋放鎖。WaitThread獲得了鎖,這才從wait()處返回繼續運行。

4.線程從wait()方法返回的前提是,獲得synchronized須要的鎖。

分析完原書的demo之後,是否有跟我一樣的感覺,以前的認識是那麽的too young too simple。

《Java並發編程的藝術》讀書筆記:等待/通知機制