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

深入理解 Synchronized 的鎖優化

開發 前端
本文首先簡單講解了 synchronized 關鍵字實現同步的原理,其實是通過 Java 虛擬機規范對于 monitorenter 和 monitorexit 的支持,從而使得 synchronized 能夠實現同步。

我們都知道 synchronized 關鍵字能實現線程安全,但是你知道這背后的原理是什么嗎?今天我們就來講一講 synchronized 實現線程同步背后的原因,以及相關的鎖優化策略吧。

背后的原理

synchronized 關鍵字經過編譯之后,會在同步塊的前后分別形成 monitorenter 和 monitorexit 這兩個字節碼指令,這兩個字節碼只需要一個指明一個要鎖定或解鎖的對象。如果 Java 程序中指明了對象參數,那么就用這個對象作為鎖。

如果沒有指定,那么就根據 synchronized 修飾的是實例方法還是類方法,去拿對應的對象實例或 Class 對象來作為鎖對象。因此我們可以知道,synchronized 關鍵字實現線程同步的背后,其實是 Java 虛擬機規范對于 monitorenter 和 monitorexit 的定義。

在 Java 虛擬機規范對 monitorenter 和 monitorexit 的行為描述中,有兩點需要特別注意。

synchronized 同步塊對同一條線程是可沖入的,也就是不會出現自己把自己鎖死的問題。

同步課在已進入的線程執行完之前,會阻塞后面其他線程的進入。

synchronized 關鍵字在 JDK1.6 版本之前,是通過操作系統的 Mutex Lock 來實現同步的。而操作系統的 Mutex Lock 是操作系統級別的方法,需要切換到內核態來執行。這就需要從用戶態轉換到內核態中,因此我們說 synchronized 同步是重量級的操作。

鎖優化

在 JDK1.6 版本中,HotSpot 虛擬機開發團隊花了很大的精力去實現各種鎖優化技術,如:適應性自旋、鎖消除、鎖粗話、偏向鎖、輕量級鎖等。其中最重要的是:自旋鎖、輕量級鎖、偏向鎖這三個,我們重點講這三個鎖優化。

自旋鎖與自適應自旋

對于重量級的同步操作來說,最大的消耗其實是內核態與用戶態的切換。很很多時候,對于共享數據的操作時間可能很短,比內核態切換到用戶態這個耗時還短。

于是有人就想:如果有多個線程并發去獲取鎖的時候,如果能讓后面那個請求鎖的線程「稍等一下」,不放棄 CPU 的執行時間,看看持有鎖的線程是否會很快釋放鎖。為了讓線程等待,我們只需讓線程執行一個忙循環(自旋),這項技術就是所謂的自旋鎖。 從理論上來看,如果所有線程都很快地獲取鎖、釋放鎖,那么自旋鎖是可以帶來較大的性能提升的。自旋鎖在 JDK 1.4.2 中就已經引入,默認自旋 10 次。但自旋鎖默認是關閉的,在 JDK 1.6 中才改為默認開啟了。

自旋等待雖然避免了線程切換的開銷,但還是要占用處理器的時間。如果鎖被占用的時間段,自旋等待的效果就會非常好。但如果鎖被長時間占用,那么自旋的線程就會白白消耗處理器的資源,從而帶來性能上的浪費。

為了解決特殊情況下自旋鎖的性能消耗問題,在 JDK1.6 的時候引入了自適應的自旋鎖。 自適應意味著自旋時間不再固定,而是由前一次在同一個鎖上的自旋時間及鎖的擁有者狀態決定。如果在同一鎖對象上,自旋等待剛剛成功獲得過鎖,那么虛擬機認為這次自旋也很有可能再次成功,進而允許線程自旋更長時間,例如自旋 100 個循環。

但如果對于某個鎖,自旋很少成功獲得過。那虛擬機為了避免浪費 CPU 資源,有可能省略掉自旋過程。有了自旋鎖,隨著程序運行和性能監控信息的不斷完善,虛擬機對鎖的狀態預測就越準,虛擬機也會變得越來越聰明。

輕量級鎖

輕量級鎖是 JDK1.6 加入的新型鎖機制,名字中的「輕量級」是相對于操作系統互斥量這個重量級鎖而言的。輕量級鎖誕生的原因,是由于對于絕大部分的鎖而言,整個同步周期都不存在競爭。如果沒有競爭的話,那就沒必要使用重量級鎖了,于是就誕生了輕量級鎖來提高效率。

對于輕量級鎖來說,其同步的流程如下:

在代碼進入同步塊的時候,如果此同步對象沒有被鎖定(鎖標志位為 01 狀態),那么虛擬機會在當前線程的棧幀中建立一個名為鎖記錄(Lock Record)的空間,用于存儲鎖對象目前的 Mark Word 拷貝。

虛擬機將使用 CAS 操作嘗試將對象的 Mark Word 更新為指向 Lock Record 的指針。如果更新動作成功了,那么線程就泳衣了該對象的鎖,并且對象 Mark Word 的鎖標志位就變成了 00,表示此對象處于輕量級鎖定狀態。

簡單地說,輕量級鎖的同步流程可以總結為:使用 CAS 操作,在線程棧幀與鎖對象建立雙向的指針。

在沒有線程競爭的情況下,輕量級鎖使用 CAS 自旋操作避免了使用互斥量的開銷,提高了效率。但如果存在鎖競爭,除了互斥量的開銷外,還額外發生了 CAS 操作。因此在有競爭的情況下,輕量級鎖會比傳統的重量級鎖更慢。

偏向鎖

偏向鎖是 JDK1.6 中引入的一項優化,它的意思是這個鎖會偏向于第一個獲得它的線程。如果在接下來的執行過程中,該鎖沒有被其他線程獲取,則持有偏向鎖的線程將永遠不需要再進行同步。 對于偏向鎖來說,其同步流程如下所示:

  • 假設當前虛擬機啟動了偏向鎖,那么當鎖對象第一次被線程獲取的時候,虛擬機將會把對象的鎖標志位設置為 01,偏向鎖位設置為 1。同時使用 CAS 操作將線程 ID 記錄在對象的 MarkWord 之中。如果 CAS 操作成功,那么持有偏向鎖的線程進入鎖對應的同步塊時,虛擬機將不再進行任何同步操作。
  • 當有另外一個線程嘗試去獲取這個鎖時,根據鎖對象目前是否處于鎖定狀態,將其恢復到未鎖定(01)或輕量級鎖定(00)狀態。隨后的同步操作,就向上面介紹的輕量級鎖那樣執行。

可以看到偏向鎖還是需要做一些 CAS 操作,但是對比起輕量級鎖來說,其要設置的內容大大減少了,因此也提高了一些效率。

偏向鎖可以提高帶有同步但無競爭的程序性能。 它同樣是一個帶有效益權衡(Trade Off)性質的優化,也就是說,它并不一定總是對程序運行有利,如果程序中大多數的鎖總是被多個不同的線程訪問,那偏向模式就是多余的。

優化后的鎖獲取流程

經過 JDK1.6 的優化,synchronized 同步機制的流程變成了:

  • 首先,synchronized 會嘗試使用偏向鎖的方式去競爭鎖資源,如果能夠競爭到偏向鎖,表示加鎖成功直接返回。
  • 如果競爭鎖失敗,說明當前鎖已經偏向了其他線程。需要將鎖升級到輕量級鎖,在輕量級鎖狀態下,競爭鎖的線程根據自適應自旋次數去嘗試搶占鎖資源。
  • 如果在輕量級鎖狀態下還是沒有競爭到鎖,就只能升級到重量級鎖。在重量級鎖狀態下,沒有競爭到鎖的線程就會被阻塞。處于鎖等待狀態的線程需要等待獲得鎖的線程來觸發喚醒。

上面的鎖獲取流程,可以用如下的示意圖來表示:

圖片

Java 對象鎖競爭流程

總結

本文首先簡單講解了 synchronized 關鍵字實現同步的原理,其實是通過 Java 虛擬機規范對于 monitorenter 和 monitorexit 的支持,從而使得 synchronized 能夠實現同步。而 synchronized 同步本質上是通過操作系統的 mutex 鎖來實現的。由于操作操作系統 mutex 鎖太過于消耗資源,因此在 JDK1.6 后 HotSpot 虛擬機做了一系列的鎖優化,其中最重要的便是:自旋鎖、輕量級鎖、偏向鎖。這三個鎖的誕生原因,以及提升的點如下表所示。

現狀

鎖名稱

收益

使用場景

大多數情況下,等待鎖的時間比操作系統 mutex 短得多

自旋鎖

減少內核態與用戶態切換的開銷

線程獲取鎖時間較短的情況

大多數情況下,鎖同步期間沒有線程競爭

輕量級鎖

與自旋鎖相比,減少了自旋時間

沒有線程競爭鎖

大多數情況下,鎖同步期間沒有線程競爭

偏向鎖

與輕量級鎖相比,減少了多余的對象復制操作

沒有線程競爭鎖

從上面表格可以看到,自旋鎖、輕量級鎖、偏向鎖,他們的優化是逐漸深入的。

  • 對于重量級鎖來說,自旋鎖減少了互斥量的內核、用戶態切換開銷。
  • 對于自旋鎖來說,輕量級鎖減少了自旋等待的時間。
  • 對于輕量級鎖來說,偏向于減少了多余的對象復制操作。
責任編輯:武曉燕 來源: 陳樹義
相關推薦

2020-11-13 08:42:24

Synchronize

2021-05-27 11:30:54

SynchronizeJava代碼

2021-07-26 07:47:37

無鎖編程CPU

2023-10-13 13:30:00

MySQL鎖機制

2023-10-31 10:51:56

MySQLMVCC并發性

2018-03-22 18:30:22

數據庫MySQL并發控制

2010-06-01 15:25:27

JavaCLASSPATH

2016-12-08 15:36:59

HashMap數據結構hash函數

2020-07-21 08:26:08

SpringSecurity過濾器

2014-07-15 17:17:31

AdapterAndroid

2012-11-22 10:11:16

LispLisp教程

2020-09-23 10:00:26

Redis數據庫命令

2019-06-25 10:32:19

UDP編程通信

2017-01-10 08:48:21

2024-02-21 21:14:20

編程語言開發Golang

2025-05-06 00:43:00

MySQL日志文件MIXED 3

2017-08-15 13:05:58

Serverless架構開發運維

2025-06-05 05:51:33

2023-10-19 11:12:15

Netty代碼

2021-02-17 11:25:33

前端JavaScriptthis
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品欧美二区 | 亚洲深夜福利 | av免费网址 | 一二三区视频 | 久久亚洲国产 | 在线播放国产视频 | 国产亚洲精品久久久久久豆腐 | 久久男人| 久久草在线视频 | 91久久视频 | 一级毛片大全免费播放 | 免费日本视频 | 精品国产黄a∨片高清在线 成人区精品一区二区婷婷 日本一区二区视频 | 久久蜜桃资源一区二区老牛 | 日本一二三区电影 | 色婷婷av一区二区三区软件 | 亚洲一区有码 | 91久久国产综合久久 | 欧美日韩中文字幕在线播放 | 午夜视频免费在线观看 | 91精品综合久久久久久五月天 | 国产一区二区精 | 久久久久国产精品午夜一区 | 国产伊人精品 | 日韩中文字幕在线观看视频 | 国产视频在线一区二区 | 亚洲欧美日韩一区二区 | 欧美精品在线播放 | 欧美伊人久久久久久久久影院 | 久久久免费精品 | 成人性生交大片免费看r链接 | 久久91av| 女同久久另类99精品国产 | 久久久久国产精品 | 久久黄网 | 国产黄色在线观看 | 精一区二区 | 一级做a爰片性色毛片视频停止 | 国产玖玖 | 亚洲成人精品一区二区 | 久久久123 |