成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java并發編程:Synchronized 的實現原理

開發 前端
隨著 JDK 的不斷發展,Synchronized 已經做了足夠多的性能優化。Synchronized 從一個開銷很大的重量級鎖被優化成一個可自動適配場景的“智能”鎖,它可以根據場景轉換成偏向鎖、輕量級鎖,萬不得已的情況下才會轉換成重量級鎖。

在剛開始學習 Java 并發編程的過程中,一遇到多線程,我們就會使用 synchronized 關鍵字。在 JDK1.5 之前,Synchronized 是一個重量級鎖,效率不盡如人意。JDK1.6 對 Synchronized 鎖進行了升級優化,引入了偏向鎖和輕量級鎖,提高了獲取鎖和釋放鎖的效率。下面我們來看一看 Synchronized 的底層實現原理吧。

Synchronized 的底層實現原理

同步原理

我們先來反編譯下面的 method1 方法:

public void method1() {
    synchronized (this) {
        System.out.println("This is the synchronized");
    }
}

在下面,我們可以看到反編譯后的 method1 代碼:

圖片圖片

從上面代碼執行過程中,我們看到代碼塊同步是使用 monitorenter 和 monitorexit 指令實現的。

monitorenter 指令是在編譯后插入到同步代碼塊的開始位置,monitorexit 是插入到方法結束的位置或者異常處。

JVM 要保證每個 monitorenter 必須有對應的 monitorexit 與之配對。任何對象都有一個 monitor 對象與之關聯,當 monitor 被對象持有后,它將處于鎖定狀態。線程執行到 monitorenter 指令時,將會嘗試獲取對象所對應的 monitor 的所有權,即嘗試獲得對象的鎖。

我們再看一下 Synchronized 方法同步的步驟:

public synchronized void method2() {
    System.out.println("This is the synchronized method");
}

圖片圖片

在上面編譯過的 method2() 方法的執行過程中,Synchronized 方法的同步是使用另外一種方式實現的,我們可以看到它被翻譯成普通的方法調用和返回 invokevirtual、return 指令。

一個被 Synchronized 修飾的方法在 JVM 底層并沒有與之對應的字節碼指令。當方法調用時,調用指令將會檢查方法的 ACC_SYNCHRONIZED 訪問標志是否被設置,如果設置了執行線程將先獲取 monitor,獲取成功之后,才能執行方法,方法執行完成再釋放 monitor。

Java 對象頭的概念

接下來,我們再來了解一下 Java 對象頭的概念。Synchronized 用的鎖就是存放在 Java 對象頭里。如果對象是數組類型,則虛擬機用 3 個字寬(Word)存儲對象頭,如果對象是非數組類型,則用 2 字寬存儲對象頭。在 32 位虛擬機中,1 字寬等于 4 字節,即 32bit。

我們看下面的表格,Java 對象頭主要包括兩部分數據:Mark Word(標記字段)、Class Pointer(類型指針)。Mark Word 用于存儲對象自身的運行時數據,它是實現輕量級鎖和偏向鎖的關鍵。Class Pointer 是對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。

圖片圖片

Java 對象頭里的 Mark Word 里默認存儲對象的 HashCode、分代年齡和鎖標記位。我們來看一下 32 位 JVM 的 Mark Word 的默認存儲結構:

圖片圖片

在運行期間,Mark Word 里存儲的數據會隨著鎖標志位的變化而變化。Mark Word 可能變化為存儲以下 4 種數據,我們來看一下存儲結構:

圖片圖片

在 64 位虛擬機下,Mark Word 是 64bit 大小的,我們看一下它的存儲結構:

圖片圖片

我們從上面的表格中看到了引入的偏向鎖和輕量級鎖。鎖級別從低到高依次為:無鎖狀態、偏向鎖狀態、輕量級鎖狀態和重量級鎖狀態,這 4 種狀態是會隨著競爭情況而逐漸升級的。鎖可以升級但不能降級,目的是提高獲得鎖和釋放鎖的效率。

下面我們來了解一下鎖升級的流程。

鎖升級

Synchronized 內部有一個隱藏的鎖升級流程,正是因為這個流程的存在,使得 Synchronized 得以發揮它的高性能特性。鎖升級中最重要的 2 個升級就是偏向鎖和輕量級鎖,下面我們分別展開討論:

偏向鎖

通常情況下,鎖不僅不存在多線程競爭,而且總是由同一線程多次獲得,為了讓線程更容易獲得鎖而引入了偏向鎖。

所謂偏向鎖,就是當一個線程訪問同步代碼塊并獲取鎖時,會在對象頭存儲鎖偏向的線程 ID。這樣,以后該線程在進入和退出同步塊時,就不需要進行 CAS 操作來加鎖和解鎖,只需要簡單地測試一下對象頭的 Mark Word 里是否存儲著指向當前線程的偏向鎖。

如果測試成功,則表示線程已經獲得了鎖;如果測試失敗,則需要再測試一下 Mark Word 中偏向鎖的標識是否設置成 1(表示當前是偏向鎖)。如果沒有設置,則使用 CAS 競爭鎖;如果設置了,則嘗試使用 CAS 將對象頭的偏向鎖指向當前線程。

偏向鎖在 Java6 和 Java7 是默認啟用的,但它在應用程序啟動幾秒鐘之后才會被激活,我們可以配置 JVM 參數來關閉延遲:-XX:BiasedLockingStartupDelay=0。如果確定應用程序里所有的鎖通常情況下處于競爭狀態,我們可以配置如下的 JVM 參數關閉偏向鎖,之后程序默認會進入輕量級鎖狀態:

-XX:-UseBiasedLocking=false

輕量級鎖

輕量級鎖不是用來替代傳統的重量級鎖的,而是在沒有多線程競爭的情況下,使用輕量級鎖能夠減少性能消耗,但是當多個線程同時競爭鎖時,輕量級鎖會膨脹為重量級鎖。

我們先來看一下輕量級鎖的加鎖過程。在線程在執行同步塊之前,JVM 會先在當前線程的棧幀中創建用于存儲鎖記錄的空間,并將對象頭中的 Mark Word 復制到鎖記錄中,官方稱為 Displaced Mark Word。然后線程嘗試使用 CAS 將對象頭中的 Mark Word 替換為指向鎖記錄的指針。如果成功,當前線程獲

得鎖,如果失敗,表示其他線程競爭鎖,當前線程便嘗試使用自旋來獲取鎖。

輕量級解鎖時,會使用原子的 CAS 操作將 Displaced Mark Word 替換回到對象頭,如果成功,則表示沒有競爭發生。如果失敗,表示當前鎖存在競爭,鎖就會膨脹成重量級鎖。

因為自旋會消耗 CPU,為了避免無用的自旋,一旦鎖升級到重量級鎖,就不會再恢復到輕量級鎖狀態。當鎖處于這個狀態下,其他線程嘗試獲取鎖時,都會被阻塞住,當持有鎖的線程釋放鎖之后會喚醒這些線程,被喚醒的線程就會進行新一輪的競爭。

下圖是兩個線程同時爭奪鎖,導致輕量級鎖膨脹的流程。

圖片圖片

鎖的優缺點對比

對于偏向鎖、輕量級鎖和重量級鎖這三者的優缺點,以及適用場景,我們可以通過下面的表格得到一個直觀的了解:

圖片圖片

總結

最后,我們來總結一下所講的主要內容。首先,我們一起學習了 Synchronized 的底層實現,Synchronized 作為一個關鍵字以它極簡的語法也帶來了易讀性;之后,我帶你了解了偏向鎖的初始化、撤銷、關閉操作和輕量級鎖的加鎖、解鎖過程;最后,我帶你分析了不同鎖的優缺點及適用場景,這些對你理解為什么 Synchronized 具備高性能是非常關鍵的。此外,不同鎖的,如偏向鎖、輕量級鎖對使用者來說是透明的,這也體現了 Synchronized 的簡單性。

隨著 JDK 的不斷發展,Synchronized 已經做了足夠多的性能優化。Synchronized 從一個開銷很大的重量級鎖被優化成一個可自動適配場景的“智能”鎖,它可以根據場景轉換成偏向鎖、輕量級鎖,萬不得已的情況下才會轉換成重量級鎖。它的應用場景也隨著這些特性逐漸豐富起來,在很多高并發場景甚至替代了 reentrantLock。

責任編輯:武曉燕 來源: 程序員技術充電站
相關推薦

2025-03-26 00:55:00

2017-02-27 10:43:07

Javasynchronize

2018-09-12 15:38:42

Javaatomic編程

2022-12-26 09:27:48

Java底層monitor

2021-03-10 15:59:39

JavaSynchronize并發編程

2017-12-06 16:28:48

Synchronize實現原理

2020-11-13 08:42:24

Synchronize

2021-01-08 08:34:09

Synchronize線程開發技術

2019-05-27 08:11:13

高并發Synchronize底層

2020-08-23 10:03:51

SynchronizeJava

2021-07-04 08:01:30

Synchronize線程安全并發編程

2020-12-04 19:28:53

CountDownLaPhaserCyclicBarri

2020-12-03 11:15:21

CyclicBarri

2020-11-30 16:01:03

Semaphore

2020-12-16 10:54:52

編程ForkJoin框架

2022-11-09 09:01:08

并發編程線程池

2020-12-09 08:21:47

編程Exchanger工具

2023-04-26 07:34:38

Java并發編程

2017-09-19 14:53:37

Java并發編程并發代碼設計

2020-09-22 12:00:23

Javahashmap高并發
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 九一视频在线观看 | 久久免费精品视频 | 国产精品国产精品国产专区不片 | 亚洲电影一区二区三区 | 亚洲一区二区三区四区五区午夜 | 精品视频一区二区三区在线观看 | 男人天堂视频在线观看 | 91视视频在线观看入口直接观看 | 97日韩精品| 日韩在线 | 美女视频三区 | 亚洲精品久久嫩草网站秘色 | 9191av| 亚洲成人自拍 | 草久久 | 青青久久久 | 国产免费一区二区三区最新6 | 亚洲精品18 | 国产精品久久二区 | 特一级毛片 | 999国产视频 | 亚洲欧美国产毛片在线 | 国产69精品久久99不卡免费版 | 少妇无套高潮一二三区 | 午夜影院普通用户体验区 | 中文字幕亚洲一区二区va在线 | 国产精品资源在线观看 | 亚洲国产精品99久久久久久久久 | 天天干天天干 | 青娱乐av| 中国一级大黄大片 | 免费精品| 日韩午夜电影 | 精品一二区 | 日韩久久久久久 | 国产在线a| 国产电影精品久久 | a级免费视频 | 精品乱子伦一区二区三区 | 久久久久国产一区二区三区不卡 | 精品国产欧美一区二区三区成人 |