Java支持同步機制的是Monitor
。Monitor就像是擁有一個特殊房間的建築,在同一時間裏,這間特殊的房間只能被一個線程擁有。html
Monitor支持兩種同步機制:java
wait-notify又能夠稱做’Singal-continue’。當線程得到 notify,這就是一個信號,線程開始擁有 monitor的全部權,可以 繼續 執行 monitor region。執行完以後,此線程釋放monitor,一個等待的線程則會得到同樣的機會
Monitor的模型以下:安全
1 表示線程剛到達 monitor region ,即 enter the monitor
2 表示線程獲取 monitor的全部權,即acquiring the monitor
3 表示線程執行了 wait,交出全部權,即releasing the monitor
4 表示原來擁有 monitor 的線程執行了 notify ,剛好被這個線程獲取全部權
5 表示線程執行完了 monitor region,即exiting the monitor
多線程
Monitor特地把等待的線程分紅了兩個部分,Entry Set和Wait Set,Entry Set表示線程剛執行到 Monitor region,而Wait Set則是因爲線程執行了wait方法而進入的區域。注意到Object的 notify 以及 notifyAll 要喚醒的對象就處於 Wait Set,換句話說,若是退出 monitor 的線程沒有執行 notify/notifyAll ,那麼只有 Entry Set 可以獲取執行的權限 。若是執行了,則Entry Set和Wait Set中全部的線程都會競爭誰最終可以獲取 monitor 的能力一個線程要離開Wait Set,要麼是原擁有 monitor 的線程執行了 notify/notifyAll,要麼是wait的時間到了,JVM 會觸發一個notifyjvm
Java可以共享的數據包括兩部分:ide
對於局部變量,他們存儲在棧中,屬於線程私有,不會存在共享一說。
單個線程能夠同時鎖住一個對象屢次,JVM會記住鎖住的總次數,每一次釋放鎖,總次數減一,只有在這個次數變成0的時候,這個鎖纔有可能被其它線程持有ui
JVM使用的指令爲this
public class SynchronizedTest { private int i=0; public void syn(){ synchronized (this){ i++; } } }
javap -c SynchronizedTest.class
執行後對應的指令以下spa
public class main.lockTest.SynchronizedTest { public main.lockTest.SynchronizedTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: iconst_0 6: putfield #2 // Field i:I 9: return public void syn(); Code: 0: aload_0 // aload_0 屬於 aload_<n> 系列指令的一種。表示獲取一個本地變量的引用,而後放入棧中 1: dup //彈出棧頂的單字節,而後入棧兩次,至關於拷貝了棧頂元素 2: astore_1 // astore_<n>系列指令的一種。從棧頂獲取對象的引用,並存入本地變量 3: monitorenter //獲取引用對象的鎖 4: aload_0 5: dup 6: getfield #2 // Field i:I 從棧中獲取對象的引用,而後獲得它的值 9: iconst_1 // iconst_<n> 的一種,將常量放入棧中 10: iadd // 從操做棧中彈出兩個integer,把他們相加,而後將結果從新存入棧中 11: putfield #2 // Field i:I 將值存入引用對象 14: aload_1 15: monitorexit // 釋放引用對象的鎖 16: goto 24 // 跳轉到下一個指令的位置 19: astore_2 20: aload_1 21: monitorexit 22: aload_2 23: athrow //從操做棧中刪掉對象的引用,並拋出這個對象的異常 24: return //執行返回 Exception table: from to target type 4 16 19 any 19 22 19 any }
注意到,若是拋出了異常,也會執行 monitorexit
。印證了不管如何,只要離開了monitor region,鎖都會被釋放線程
public class SynchronizedTest { private int i=0; public synchronized void syn(int i){ i++; } }
對應指令以下
public class main.lockTest.SynchronizedTest { public main.lockTest.SynchronizedTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: iconst_0 6: putfield #2 // Field i:I 9: return public synchronized void syn(int); Code: 0: iinc 1, 1 3: return }
能夠看到兩個區別