中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Synchronized輕量級鎖的加鎖和解鎖過程

發布時間:2021-09-08 14:50:19 來源:億速云 閱讀:183 作者:chen 欄目:大數據

本篇內容介紹了“Synchronized輕量級鎖的加鎖和解鎖過程”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

一、重量級鎖

  上篇文章中向大家介紹了Synchronized的用法及其實現的原理。現在我們應該知道,Synchronized是通過對象內部的一個叫做監視器鎖(monitor)來實現的。但是監視器鎖本質又是依賴于底層的操作系統的Mutex Lock來實現的。而操作系統實現線程之間的切換這就需要從用戶態轉換到核心態,這個成本非常高,狀態之間的轉換需要相對比較長的時間,這就是為什么Synchronized效率低的原因。因此,這種依賴于操作系統Mutex Lock所實現的鎖我們稱之為“重量級鎖”。JDK中對Synchronized做的種種優化,其核心都是為了減少這種重量級鎖的使用。JDK1.6以后,為了減少獲得鎖和釋放鎖所帶來的性能消耗,提高性能,引入了“輕量級鎖”和“偏向鎖”。

二、輕量級鎖 

  鎖的狀態總共有四種:無鎖狀態、偏向鎖、輕量級鎖和重量級鎖。隨著鎖的競爭,鎖可以從偏向鎖升級到輕量級鎖,再升級的重量級鎖(但是鎖的升級是單向的,也就是說只能從低到高升級,不會出現鎖的降級)。JDK 1.6中默認是開啟偏向鎖和輕量級鎖的,我們也可以通過-XX:-UseBiasedLocking來禁用偏向鎖。鎖的狀態保存在對象的頭文件中,以32位的JDK為例:

Synchronized輕量級鎖的加鎖和解鎖過程

  “輕量級”是相對于使用操作系統互斥量來實現的傳統鎖而言的。但是,首先需要強調一點的是,輕量級鎖并不是用來代替重量級鎖的,它的本意是在沒有多線程競爭的前提下,減少傳統的重量級鎖使用產生的性能消耗。在解釋輕量級鎖的執行過程之前,先明白一點,輕量級鎖所適應的場景是線程交替執行同步塊的情況,如果存在同一時間訪問同一鎖的情況,就會導致輕量級鎖膨脹為重量級鎖。

1、輕量級鎖的加鎖過程

  (1)在代碼進入同步塊的時候,如果同步對象鎖狀態為無鎖狀態(鎖標志位為“01”狀態,是否為偏向鎖為“0”),虛擬機首先將在當前線程的棧幀中建立一個名為鎖記錄(Lock Record)的空間,用于存儲鎖對象目前的Mark Word的拷貝,官方稱之為 Displaced Mark Word。這時候線程堆棧與對象頭的狀態如圖2.1所示。

  (2)拷貝對象頭中的Mark Word復制到鎖記錄中。

  (3)拷貝成功后,虛擬機將使用CAS操作嘗試將對象的Mark Word更新為指向Lock Record的指針,并將Lock record里的owner指針指向object mark word。如果更新成功,則執行步驟(3),否則執行步驟(4)。

  (4)如果這個更新動作成功了,那么這個線程就擁有了該對象的鎖,并且對象Mark Word的鎖標志位設置為“00”,即表示此對象處于輕量級鎖定狀態,這時候線程堆棧與對象頭的狀態如圖2.2所示。

  (5)如果這個更新操作失敗了,虛擬機首先會檢查對象的Mark Word是否指向當前線程的棧幀,如果是就說明當前線程已經擁有了這個對象的鎖,那就可以直接進入同步塊繼續執行。否則說明多個線程競爭鎖,輕量級鎖就要膨脹為重量級鎖,鎖標志的狀態值變為“10”,Mark Word中存儲的就是指向重量級鎖(互斥量)的指針,后面等待鎖的線程也要進入阻塞狀態。 而當前線程便嘗試使用自旋來獲取鎖,自旋就是為了不讓線程阻塞,而采用循環去獲取鎖的過程。

 Synchronized輕量級鎖的加鎖和解鎖過程

                     圖2.1 輕量級鎖CAS操作之前堆棧與對象的狀態

Synchronized輕量級鎖的加鎖和解鎖過程

                                        圖 2.3三者的轉換圖

  該圖主要是對上述內容的總結,如果對上述內容有較好的了解的話,該圖應該很容易看懂。

四、其他優化 

1、適應性自旋(Adaptive Spinning):從輕量級鎖獲取的流程中我們知道當線程在獲取輕量級鎖的過程中執行CAS操作失敗時,是要通過自旋來獲取重量級鎖的。問題在于,自旋是需要消耗CPU的,如果一直獲取不到鎖的話,那該線程就一直處在自旋狀態,白白浪費CPU資源。解決這個問題最簡單的辦法就是指定自旋的次數,例如讓其循環10次,如果還沒獲取到鎖就進入阻塞狀態。但是JDK采用了更聰明的方式——適應性自旋,簡單來說就是線程如果自旋成功了,則下次自旋的次數會更多,如果自旋失敗了,則自旋的次數就會減少。

2、鎖粗化(Lock Coarsening):鎖粗化的概念應該比較好理解,就是將多次連接在一起的加鎖、解鎖操作合并為一次,將多個連續的鎖擴展成一個范圍更大的鎖。舉個例子:

1 package com.paddx.test.string;
 2 
 3 public class StringBufferTest {
 4     StringBuffer stringBuffer = new StringBuffer();
 5 
 6     public void append(){
 7         stringBuffer.append("a");
 8         stringBuffer.append("b");
 9         stringBuffer.append("c");
10     }
11 }

  這里每次調用stringBuffer.append方法都需要加鎖和解鎖,如果虛擬機檢測到有一系列連串的對同一個對象加鎖和解鎖操作,就會將其合并成一次范圍更大的加鎖和解鎖操作,即在第一次append方法時進行加鎖,最后一次append方法結束后進行解鎖。

3、鎖消除(Lock Elimination):鎖消除即刪除不必要的加鎖操作。根據代碼逃逸技術,如果判斷到一段代碼中,堆上的數據不會逃逸出當前線程,那么可以認為這段代碼是線程安全的,不必要加鎖。看下面這段程序:

1 package com.paddx.test.concurrent;
 2 
 3 public class SynchronizedTest02 {
 4 
 5     public static void main(String[] args) {
 6         SynchronizedTest02 test02 = new SynchronizedTest02();
 7         //啟動預熱
 8         for (int i = 0; i < 10000; i++) {
 9             i++;
10         }
11         long start = System.currentTimeMillis();
12         for (int i = 0; i < 100000000; i++) {
13             test02.append("abc", "def");
14         }
15         System.out.println("Time=">雖然StringBuffer的append是一個同步方法,但是這段程序中的StringBuffer屬于一個局部變量,并且不會從該方法中逃逸出去,所以其實這過程是線程安全的,可以將鎖消除。下面是我本地執行的結果:  為了盡量減少其他因素的影響,這里禁用了偏向鎖(-XX:-UseBiasedLocking)。通過上面程序,可以看出消除鎖以后性能還是有比較大提升的。  注:可能JDK各個版本之間執行的結果不盡相同,我這里采用的JDK版本為1.6。1:減少鎖持有時間          例如:對一個方法加鎖,不如對方法中需要同步的幾行代碼加鎖;    2:減小鎖粒度        例如:ConcurrentHashMap采取對segment加鎖而不是整個map加鎖,提高并發性;    3:鎖分離         根據同步操作的性質,把鎖劃分為的讀鎖和寫鎖,讀鎖之間不互斥,提高了并發性。 五、總結   本文重點介紹了JDk中采用輕量級鎖和偏向鎖等對Synchronized的優化,但是這兩種鎖也不是完全沒缺點的,比如競爭比較激烈的時候,不但無法提升效率,反而會降低效率,因為多了一個鎖升級的過程,這個時候就需要通過-XX:-UseBiasedLocking來禁用偏向鎖。下面是這幾種鎖的對比:鎖優點缺點適用場景偏向鎖加鎖和解鎖不需要額外的消耗,和執行非同步方法比僅存在納秒級的差距。如果線程間存在鎖競爭,會帶來額外的鎖撤銷的消耗。適用于只有一個線程訪問同步塊場景。輕量級鎖競爭的線程不會阻塞,提高了程序的響應速度。如果始終得不到鎖競爭的線程使用自旋會消耗CPU。追求響應時間。同步塊執行速度非常快。重量級鎖線程競爭不使用自旋,不會消耗CPU。線程阻塞,響應時間緩慢。追求吞吐量。同步塊執行速度較長。

“Synchronized輕量級鎖的加鎖和解鎖過程”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

积石山| 东明县| 牡丹江市| 扎囊县| 军事| 伊吾县| 托克逊县| 时尚| 昭平县| 交城县| 连州市| 开封市| 镇远县| 漠河县| 常德市| 木兰县| 红安县| 屏山县| 克拉玛依市| 文化| 吉安市| 饶平县| 大足县| 土默特右旗| 枝江市| 郯城县| 淮北市| 沂源县| 黄骅市| 高雄县| 兴隆县| 巴林右旗| 洱源县| 公安县| 顺义区| 耒阳市| 临汾市| 英德市| 九龙县| 金溪县| 松滋市|