程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 重新認識synchronized(下),重新認識你自己下載

重新認識synchronized(下),重新認識你自己下載

編輯:JAVA綜合教程

重新認識synchronized(下),重新認識你自己下載



synchronized既保證原子性,又保證內存可見性,是一種線程同步的方式,是鎖機制的一種java實現。synchronized的實現基於JVM底層,JVM是基於monitor實現的,而monitor的實現依賴於操作系統的互斥實現。

語義

synchronized語義是同步,但同步有兩層含義:

互斥保證在線程退出前,所有對象狀態變更都對其他線程不可見;可見保證在線程進入同步代碼塊時,可以看到上一個線程對對象狀態變更的最終狀態。

線程安全與同步

線程安全表明在多線程環境中,不會有多個線程同時訪問共享數據。
線程同步是線程訪問類和實例字段變量,和其他共享資源的一種串行化行為,確保在同一時間只能有一個線程訪問資源。舉個栗子,春運火車票只剩下最後一張火車票,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 }

鎖的種類

java synchronized鎖升級java synchronized鎖升級
JDK1.6中對synchronized優化引入了偏向鎖,輕量級鎖,重量級鎖。鎖的升級過程是單方向的,只允許從低到高升級,不允許降級。

重量級鎖(Heavyweight Lock)是將程序運行交出控制權,將線程掛起,由操作系統來負責線程間的調度,負責線程的阻塞和執行。這樣會出現頻繁地對線程運行狀態的切換,線程的掛起和喚醒,消耗大量的系統資源,導致性能低下。

輕量級鎖(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中對應不同的字段。
java synchronized不同級別鎖中的Mark Wordjava synchronized不同級別鎖中的Mark Word

我是葛一凡,希望對你有用。

參考

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved