1. 程式人生 > >Synchronized的實現原理(一)

Synchronized的實現原理(一)

synchronized,是Java中用於解決併發情況下資料同步訪問的一個很重要的關鍵字。當我們想要保證一個共享資源在同一時間只會被一個執行緒訪問到時,我們可以在程式碼中使用synchronized關鍵字對類或者物件加鎖。那麼,本文來介紹一下synchronized關鍵字的實現原理是什麼。在閱讀本文之間,建議先看下Java虛擬機器是如何執行執行緒同步的

反編譯

眾所周知,在Java中,synchronized有兩種使用形式,同步方法和同步程式碼塊。程式碼如下:

/**
 * @author Hollis 17/11/9.
 */
public class SynchronizedTest {

    public synchronized void doSth(){
        System.out.println("Hello World");
    }

    public void doSth1(){
        synchronized (SynchronizedTest.class){
            System.out.println("Hello World");
        }
    }
}

我們先來使用Javap來反編譯以上程式碼,結果如下(部分無用資訊過濾掉了):

  public synchronized void doSth();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String Hello World
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return

  public void doSth1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: ldc           #5                  // class com/hollis/SynchronizedTest
         2: dup
         3: astore_1
         4: monitorenter
         5: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         8: ldc           #3                  // String Hello World
        10: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        13: aload_1
        14: monitorexit
        15: goto          23
        18: astore_2
        19: aload_1
        20: monitorexit
        21: aload_2
        22: athrow
        23: return

反編譯後,我們可以看到Java編譯器為我們生成的位元組碼。在對於doSthdoSth1的處理上稍有不同。也就是說。JVM對於同步方法和同步程式碼塊的處理方式不同。

對於同步方法,JVM採用ACC_SYNCHRONIZED標記符來實現同步。 對於同步程式碼塊。JVM採用monitorentermonitorexit兩個指令來實現同步。

關於這部分內容,在JVM規範中也可以找到相關的描述。

同步方法

The Java® Virtual Machine Specification中有關於方法級同步的介紹:

Method-level synchronization is performed implicitly, as part of method invocation and return. A synchronized method is distinguished in the run-time constant pool's methodinfo structure by the ACC

SYNCHRONIZED flag, which is checked by the method invocation instructions. When invoking a method for which ACC_SYNCHRONIZED is set, the executing thread enters a monitor, invokes the method itself, and exits the monitor whether the method invocation completes normally or abruptly. During the time the executing thread owns the monitor, no other thread may enter it. If an exception is thrown during invocation of the synchronized method and the synchronized method does not handle the exception, the monitor for the method is automatically exited before the exception is rethrown out of the synchronized method.

主要說的是: 方法級的同步是隱式的。同步方法的常量池中會有一個ACC_SYNCHRONIZED標誌。當某個執行緒要訪問某個方法的時候,會檢查是否有ACC_SYNCHRONIZED,如果有設定,則需要先獲得監視器鎖,然後開始執行方法,方法執行之後再釋放監視器鎖。這時如果其他執行緒來請求執行方法,會因為無法獲得監視器鎖而被阻斷住。值得注意的是,如果在方法執行過程中,發生了異常,並且方法內部並沒有處理該異常,那麼在異常被拋到方法外面之前監視器鎖會被自動釋放。

同步程式碼塊

同步程式碼塊使用monitorentermonitorexit兩個指令實現。The Java® Virtual Machine Specification中有關於這兩個指令的介紹:

monitorenter

Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as follows:

If the entry count of the monitor associated with objectref is zero, the thread enters the monitor and sets its entry count to one. The thread is then the owner of the monitor.

If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count.

If another thread already owns the monitor associated with objectref, the thread blocks until the monitor's entry count is zero, then tries again to gain ownership.

monitorexit

The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.

The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.

大致內容如下: 可以把執行monitorenter指令理解為加鎖,執行monitorexit理解為釋放鎖。 每個物件維護著一個記錄著被鎖次數的計數器。未被鎖定的物件的該計數器為0,當一個執行緒獲得鎖(執行monitorenter)後,該計數器自增變為 1 ,當同一個執行緒再次獲得該物件的鎖的時候,計數器再次自增。當同一個執行緒釋放鎖(執行monitorexit指令)的時候,計數器再自減。當計數器為0的時候。鎖將被釋放,其他執行緒便可以獲得鎖。

總結

同步方法通過ACC_SYNCHRONIZED關鍵字隱式的對方法進行加鎖。當執行緒要執行的方法被標註上ACC_SYNCHRONIZED時,需要先獲得鎖才能執行該方法。

同步程式碼塊通過monitorentermonitorexit執行來進行加鎖。當執行緒執行到monitorenter的時候要先獲得所鎖,才能執行後面的方法。當執行緒執行到monitorexit的時候則要釋放鎖。

每個物件自身維護這一個被加鎖次數的計數器,當計數器數字為0時表示可以被任意執行緒獲得鎖。當計數器不為0時,只有獲得鎖的執行緒才能再次獲得鎖。即可重入鎖。

至此,我們大致瞭解了Synchronized的原理。但是還有幾個問題並沒有介紹清楚,比如,Monitor到底是什麼?物件的鎖的狀態儲存在哪裡? 別急,後面會再介紹。


相關推薦

Synchronized實現原理

synchronized,是Java中用於解決併發情況下資料同步訪問的一個很重要的關鍵字。當我們想要保證一個共享資源在同一時間只會被一個執行緒訪問到時,我們可以在程式碼中使用synchronized關鍵字對類或者物件加鎖。那麼,本文來介紹一下synchronized關鍵字的實

JDK9 ConcurrentHashMap實現原理

文章目錄 JDK9 ConcurrentHashMap實現原理(一) 資料結構 私有屬性 靜態屬性 相關節點 構造器 Hash值計算 新增元素 初始化陣列

java併發機制的底層實現原理:volatile深入分析

     java程式碼最終會被類載入器載入到JVM中,然後轉化為彙編指令在CPU上執行。java中所使用的併發機制依賴於JVM的實現和CPU的指令。 1.volatile的應用 volatile是一個輕量級的synchronize,它保證了共享變數的可見性,確保了所有執

Android--推送機制實現原理

簡介 Pull模式  傳統的移動端APP從伺服器獲取資訊的途徑是通過主動向伺服器發起Request請求,通常稱這種模式為Pull模式,這種模式移動端與伺服器端維持的是短連線,也就是需要時由移動端主動

Spring原始碼學習之IOC容器實現原理-DefaultListableBeanFactory

從這個繼承體系結構圖來看,我們可以發現DefaultListableBeanFactory是第一個非抽象類,非介面類。實際IOC容器。所以這篇部落格以DefaultListableBeanFactoryIOC容器為基準進行IOC原理解析。 一.兩個重要介面 前面已經分析了BeanFactor,它的三個直接子

Java併發4深入分析java執行緒池框架及實現原理

先說說我個人對執行緒池的理解:執行緒池顧名思義是一個裝有很多執行緒的池子,這個池子維護著從執行緒建立到銷燬的怎個生命週期以及執行緒的分配,使用者只需要把任務提交給這個執行緒池而不用去關心執行緒池如何建立執行緒,執行緒池會自己給這些任務分配執行緒資源來完成任務。 java的E

購物車實現原理

購物車相當於現實中超市的購物車,不同的是一個是實體車,一個是虛擬車而已。使用者可以在購物網站的不同頁面之間跳轉,以選購自己喜愛的商品,點選購買時,該商品就自動儲存到你的購物車中,重複選購後,最後將選中的所有商品放在購物車中統一到付款臺結賬,這也是儘量讓客戶體驗到現實生活中購

OkHttp的實現原理之同步

最近我做的一個專案的網路框架就是選用的OkHttp,僅僅只是呼叫一下Api當然是不夠的,想要駕馭它並靈活的運用則需要了解它的實現原理,那麼就需要去看它的原始碼了。 Okhttp有兩種請求方式: 1. 同步請求: execute(); 2. 非同步請求 :

face++人臉識別介面實現原理

背景: 市面上,能夠提供人臉識別解決方案的公司主要有,百度,科大訊飛,曠世face++,還有已經被facebook收購的face.com。這裡涉及到的是曠世科技的人臉識別技術。曠世科技人臉識別技術,在國內得到了很廣泛運用,其中最有名是,支付寶的刷臉驗證登入技術

正則表示式的實現原理

開發十年,就只剩下這套架構體系了! >>>   

從微信小程式開發者工具原始碼看實現原理- - 小程式架構設計

使用微信小程式開發已經很長時間了,對小程式開發已經相當熟練了;但是作為一名對技術有追求的前端開發,僅僅熟練掌握小程式的開發感覺還是不夠的,我們應該更進一步的去理解其背後實現的原理以及對應的考量,這可能會解釋我們在開發過程中遇到的一些疑惑,比如為啥小程式不能操作dom、小程式是web技術渲染還是native技術

人工智慧原理——KNN最近鄰網路實現

一 目標:在不呼叫除了numpy之外的高階庫的情況下使用KNN最近鄰演算法實現對句子的分類和迴歸 二 演算法原理        最簡單最初級的分類器是將全部訓練資料的類別都記錄下來,如果測試物件的屬性和某個訓練物件的屬性完全匹配,就可以進行分類。顯然,絕大部分測試物件都不

Redux原理:Store實現分析

Redux原理(一):Store實現分析 寫在前面 寫React也有段時間了,一直也是用Redux管理資料流,最近正好有時間分析下原始碼,一方面希望對Redux有一些理論上的認識;另一方面也學習下框架程式設計的思維方式。 Redux如何管理s

socket 由淺入深系列------ 原理

ora internal 概念 pro tcp協議 如何 控制 是的 depends 來自:網絡整理 個人覺得寫一個網絡應用程序沒有是一件非常easy的事。其實,我們剛開始的時候總覺得的原則: 建立------》連接套接字-------》接受一個連接----》發送數據

solr搜索之入門及原理

solr solr入門 1 solr簡介solr官方文檔:http://wiki.apache.org/solr/DataImportHandler 下載地址:http://www.apache.org/dyn/closer.cgi/lucene/solr/2 solr入門我們使

Zookeeper之Zookeeper底層客戶端架構實現原理轉載

一次 描述 綁定 機制 一個 ini fin 源碼 receive Zookeeper的Client直接與用戶打交道,是我們使用Zookeeper的interface。了解ZK Client的結構和工作原理有利於我們合理的使用ZK,並能在使用中更早的發現問題。本文將在研究源

Spring技術內幕:Spring AOP的實現原理

dede ide configure ida mini == src min dem 生成SingleTon代理對象在getSingleTonInstance方法中完畢,這種方法時ProxyFactoryBean生成AopProxy對象的入口。代理對象會

單點登錄SSO的實現原理

客戶 解決方案 bus 應用集成 eight 冗余 請求 效率 att 單點登錄SSO(Single Sign On)說得簡單點就是在一個多系統共存的環境下,用戶在一處登錄後,就不用在其他系統中登錄,也就是用戶的一次登錄能得到其他所有系統的信任。單點登錄在大型網站裏使用得非

QR二維碼原理

info 分別是 最大 mask 多字節字符 包含 多字節 版本 錯誤 一、什麽是QR碼 QR碼屬於矩陣式二維碼中的一個種類,由DENSO(日本電裝)公司開發,由JIS和ISO將其標準化。QR碼的樣子其實在很多場合已經能夠被看到了,我這還是貼個圖展示一下: 這個圖如果被正確

React-Native系列Android——Native與Javascript通信原理

from 直接 最新 一點 明顯 rem 負責 receive esp React-Native最核心的是Native與Javascript之間的通信,並且是雙向通信