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