java併發編程(2)——wait和notify解析

   JAVA的進程同步是經過synchronized()來實現的,須要說明的是,JAVA的synchronized()方法相似於操做系統概念中的互斥內存塊,在JAVA中的Object類型中,都是帶有一個內存鎖的,在有線程獲取該內存鎖後,其它線程沒法訪問該內存,從而實現JAVA中簡單的同步、互斥操做。明白這個原理,就能理解爲何synchronized(this)與synchronized(static XXX)的區別了,synchronized就是針對內存區塊申請內存鎖,this關鍵字表明類的一個對象,因此其內存鎖是針對相同對象的互斥操做,而static成員屬於類專有,其內存空間爲該類全部成員共有,這就致使synchronized()對static成員加鎖,至關於對類加鎖,也就是在該類的全部成員間實現互斥,在同一時間只有一個線程可訪問該類的實例。若是隻是簡單的想要實如今JAVA中的線程互斥,明白這些基本就已經夠了。但若是須要在線程間相互喚醒的話就須要藉助Object.wait(), Object.nofity()了。java


wait與notify是java同步機制中重要的組成部分。結合與synchronized關鍵字使用,能夠創建不少優秀的同步模型。
     synchronized(this){}等價與public synchronized void method(){.....}
     同步分爲類級別和對象級別,分別對應着類鎖和對象鎖
類鎖是每一個類只有一個,若是static的方法被synchronized關鍵字修飾則在這個方法被執行前必須得到類鎖;對象鎖類同。(static synchronized是類級別的,非static的synchronized和synchronized塊都是對象級別的,即做用在同一new出來的對象上)
     首先,調用一個Object的wait與notify/notifyAll的時候,必須保證調用代碼對該Object是同步的,也就是說必須在做用等同於synchronized(obj){......}的內部纔可以去調用obj的wait與notify/notifyAll三個方法,不然就會報錯:
     java.lang.IllegalMonitorStateException: current thread not owner
     在調用wait的時候,線程自動釋放其佔有的對象鎖,同時不會去申請對象鎖。當線程被喚醒的時候,它纔再次得到了去得到對象鎖的權利。
     因此,notify與notifyAll沒有太多的區別,只是notify僅喚醒一個線程並容許它去得到鎖,notifyAll是喚醒全部等待這個對象的線程並容許它們去得到對象鎖,只要是在synchronied塊中的代碼,沒有對象鎖是步履維艱的。其實喚醒一個線程就是從新容許這個線程去得到對象鎖並向下運行。
       順便說一下notifyall,雖然是對每一個wait的對象都調用一次notify,可是這個仍是有順序的,每一個對象都保存這一個等待對象鏈,調用的順序就是這個鏈的順序。其實啓動等待對象鏈中各個線程的也是一個線程,在具體應用的時候,須要注意一下。
ide


應用實例:函數

創建三個線程,A線程打印10次A,B線程打印10次B,C線程打印10次C,要求線程同時運行,交替打印10次ABC。這個問題用Object的wait(),notify()就能夠很方便的解決。this


package cn.com.thread;

/**
 * Description: <交替打印10次ABC>. <br>
 * <p>
 * <使用說明>
 * </p>
 * Makedate:2014-4-12 下午2:14:19
 * 
 * @author gaowenming
 * @version V1.0
 */
public class WaitAndNotifyTest {

	/**
	 * 描述 : <描述函數實現的功能>. <br>
	 * <p>
	 * <使用方法說明>
	 * </p>
	 * 
	 * @param args
	 */
	public static void main(String[] args) {

		final PrintABC printAbc = new PrintABC();

		// 循環加載外層
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						printAbc.printA(); // printA
					} catch (Exception e) {
						e.printStackTrace();
					}

				}
			}).start();

			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						printAbc.printB();// printB
					} catch (Exception e) {
						e.printStackTrace();
					}

				}
			}).start();

			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						printAbc.printC();// printC
					} catch (Exception e) {
						e.printStackTrace();
					}

				}
			}).start();

		}

	}

}

/**
 * 
 * 
 * @Description: 交替打印10次ABC
 * @author gaowenming
 * @date 2014-4-12 下午2:17:11
 * 
 */
class PrintABC {
	// 定義全局變量
	boolean a = true;
	boolean b = false;
	boolean c = false;

	public synchronized void printA() throws Exception {
		// 用while,表示一直等待
		while (!a) {
			this.wait();
		}
		System.out.print("A");
		a = false;
		b = true;

		// 執行完後喚醒其餘等待的線程
		notifyAll();

	}

	public synchronized void printB() throws Exception {
		while (!b) {
			this.wait();
		}
		System.out.print("B");
		b = false;
		c = true;
		notifyAll();
	}

	public synchronized void printC() throws Exception {
		while (!c) {
			this.wait();
		}
		System.out.println("C");
		c = false;
		a = true;
		notifyAll();
	}
}


運行結果:spa

ABC操作系統

ABC線程

ABCcode

ABC對象

ABC進程

ABC

ABC

ABC

ABC

ABC

相關文章
相關標籤/搜索