synchronized既保證原子性,又保證內存可見性,是一種線程同步的方式,是鎖機制的一種java實現。synchronized的實現基於JVM底層,JVM是基於monitor實現的,而monitor的實現依賴於操做系統的互斥實現。
html
synchronized語義是同步,但同步有兩層含義:java
互斥保證在線程退出前,全部對象狀態變動都對其餘線程不可見;可見保證在線程進入同步代碼塊時,能夠看到上一個線程對對象狀態變動的最終狀態。編程
線程安全代表在多線程環境中,不會有多個線程同時訪問共享數據。
線程同步是線程訪問類和實例字段變量,和其餘共享資源的一種串行化行爲,確保在同一時間只能有一個線程訪問資源。舉個栗子,春運火車票只剩下最後一張火車票,A,B都要搶這張火車票,怎麼解決這個問題防止超賣呢?把資源保護起來,讓A,B排隊來買火車票。
線程安全是屬性,線程同步是方式。安全
synchronized同步代碼塊是經過monitorenter和monitorexit指令實現的,而synchronized同步方法是基於ACC_SYCHRONIZED標誌,同步方法被調用時JVM會檢查這個標誌。monitorenter標記臨界區的開始,線程執行到 monitorenter 指令時,將會嘗試獲取對象所對應的 monitor 的全部權;monitorexit標記臨界區的結束,線程執行到 monitorexit 指令時,將釋放對象所對應的 monitor 的全部權。多線程
1 public class SynchronizedMethod { 2 public synchronized void methodA() { 3 System.out.println("MethodA start"); 4 5 } 6 }
將這段代碼經過 javap -c
反編譯一下,重點關注一下編譯後的第3行和第13行。併發
1 Compiled from "SynchronizedTest.java" 2 public class com.memory.SynchronizedTest { 3 public com.memory.SynchronizedTest(); 4 Code: 5 0: aload_0 6 1: invokespecial #1 // Method java/lang/Object."<init>":()V 7 4: return 8 9 public void methodA(); 10 Code: 11 0: aload_0 12 1: dup 13 2: astore_1 14 3: monitorenter 15 4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 16 7: ldc #3 // String MethodA start 17 9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 18 12: aload_1 19 13: monitorexit 20 14: goto 22 21 17: astore_2 22 18: aload_1 23 19: monitorexit 24 20: aload_2 25 21: athrow 26 22: return 27 Exception table: 28 from to target type 29 4 14 17 any 30 17 20 17 any 31 }
鎖的種類oracle
重量級鎖(Heavyweight Lock)是將程序運行交出控制權,將線程掛起,由操做系統來負責線程間的調度,負責線程的阻塞和執行。這樣會出現頻繁地對線程運行狀態的切換,線程的掛起和喚醒,消耗大量的系統資源,致使性能低下。post
輕量級鎖(lightweight Locking)是相對於重量級鎖而言的,在synchronized實現中使用自旋的方式,實際是經過CPU自旋等待的方式替代線程切換,競爭的線程不會所以而阻塞,避免阻塞喚醒形成的CPU負荷。採用自旋的方式有利有弊,當鎖佔用的時間較短時,較少次數的自旋等待就能夠獲取鎖;但在鎖佔用的時間較長時,自旋會白白浪費大量的CPU資源。所以自旋的次數有必定要在限定以內,自旋失敗就會當即將鎖升級爲重量級鎖,稱爲鎖膨脹。性能
偏向鎖(Biased Locking )從字面含義是這把鎖是有私心的,會傾向於上次訪問的線程。Hotspot的做者在他的論文《QRL-OpLocks-BiasedLocking》中闡述到,研究發現大多數狀況下不存在多線程爭奪共享資源,並且老是由同一線程屢次得到,考慮到CAS (Compare-And-Swap)指令在獲取Java監視器時會形成較大的CPU延遲,爲了讓線程得到鎖的代價更低而引入了偏向鎖。
64位虛擬機中,標記字段(Mark Word)中包含哈希嗎(HashCode,存放31bits對象的hashcode值),GC分代年齡(Generational GC Age,4bits,所以分代年齡最高爲15),偏向線程ID,偏向鎖標記。
synchronized鎖的四個狀態:無鎖狀態,偏向鎖,輕量級鎖和重量級鎖,在Mark Word中對應不一樣的字段。
我是葛一凡,但願對你有用。