Java併發編程基礎-鎖-synchonized

  • 前言:

      synchonized是java中廣泛意義的鎖,通常都會稱之爲重量鎖。自從JDK1.6開始對synchonized進行優化,synchonized在某些狀況下也會轉變爲偏向鎖、輕量鎖、重量鎖能夠認爲synchonized關鍵字是幾種鎖的封裝。java

  • 用法:
    • 修飾方法,當有線程調用這個方法時,會鎖定該方法的實例對象,不容許其餘線程進行操做,若是方法是靜態的,鎖的是該類型的Class對象,示例以下:
      public synchronized void methodName
    • 修飾代碼塊,當有線程使用代碼塊時,會鎖定代碼塊,不容許其餘線程進行操做,鎖的是()裏面的對象,示例以下:
      public void methodName(){
          synchronized (lockObj){
              //logic
          }
      }
      代碼中的lockObj爲一個對象,被稱爲監視器(monitor),能夠使用this,或者任意Object對象,用於存儲鎖的相關信息。
  • 原理:
           使用javap反編譯擁有synchonized代碼塊的方法,發現synchonized代碼塊開始和結束(有異常)的地方分別有monitorentermonitorexit指令,以下圖所示:



          當執行到monitorenter時,獲取monitor(即代碼中的lockObj)的全部權,執行到monitorexit,釋放monitor的全部權,synchonized方法原理也相似。
  • 底層實現:
          synchonized將鎖的信息存在了Java對象頭的MarkWord裏,32位和64位操做系統Java對象頭的結構以下圖所示:



          前面提到synchonized關鍵字包含有幾種狀態,從無鎖狀態->偏向鎖->輕量鎖->重量鎖 依次變化,鎖只能升級,不能降級,32位虛擬機MarkWord中存儲的鎖狀態信息以下:



          推薦使用openjdk的JOL包來觀察MarkWord,一個無鎖狀態的截圖以下(圖中01爲鎖標識位):



          幾種鎖的狀態升級過程比較複雜,另開一貼具體說明。
  • 坑:
    • 使用synchronized修飾代碼塊時,lock對象須要是全局的對象,若是lockObj在代碼塊所在方法內進行初始化,那麼鎖定無效,由於使用的鎖信息存儲在了不一樣的對象中。
    • 使用JOL觀察MarkWord時,低位優先打印,所以上面無鎖狀態的截圖中01纔是鎖標誌位。

參考書籍及網址:編程

  • 《Java併發編程的藝術》
  • 《深刻理解Java虛擬機》

PS:研究基於MAC+Idea+JDK1.8 64位併發

Keep Calm and Carry on!優化

相關文章
相關標籤/搜索