synchronized與 Java內置鎖(未寫完)

文章目錄

  • 一、 synchronized 關鍵字
  • 二、Java對象結構
    • 1. 對象頭
    • 2. 對象體
    • 3. 對齊字節
    • 4. 對象頭中的字段長度
    • 5. Mark Word 的結構信息
    • 6. 使用 JOL 工具查看對象的布局
  • 三、Java 內置鎖機制
    • 3.1 內置鎖的演進過程
      • 1. 無鎖狀態
      • 2. 偏向鎖狀態
      • 3. 輕量級鎖狀態
      • 4. 重量級鎖狀態

一、 synchronized 關鍵字

在Java中,synchronized關鍵字通過內置鎖(也稱為監視器鎖或互斥鎖)機制實現線程間的互斥訪問。具體來說,它確保在同一時刻只有一個線程能夠執行特定的同步代碼塊或方法。

  1. Java內置鎖

每個對象都有一個與之關聯的內置鎖(monitor lock)。當一個線程進入synchronized方法或代碼塊時,它會嘗試獲取該對象的內置鎖。如果成功獲取到鎖,則該線程可以繼續執行;否則,線程將被阻塞并放入等待隊列中,直到鎖被釋放。

  1. 鎖的狀態
  • 無鎖狀態:對象處于未鎖定狀態,任何線程都可以嘗試獲取該對象的鎖。

  • 偏向鎖狀態:JVM優化的一種方式,在幾乎沒有競爭的情況下,鎖會偏向于第一個獲取它的線程,減少不必要的CAS操作。

  • 輕量級鎖狀態:當有多個線程嘗試獲取同一個鎖但競爭不激烈時,JVM會使用CAS操作來避免重量級鎖帶來的開銷。

  • 重量級鎖狀態:在高競爭情況下,鎖會膨脹為重量級鎖,涉及操作系統級別的線程掛起和恢復,帶來較高的性能開銷。

synchronized的使用方式有:

1. synchronized 修飾實例方法(非靜態方法)

當一個實例方法被聲明為synchronized時,它會鎖定調用該方法的對象(即當前對象,this)。這意味著同一時間只能有一個線程執行這個實例方法。

public class SynchronizedExample {public synchronized void synchronizedInstanceMethod() {// 同步代碼塊System.out.println(Thread.currentThread().getName() + " is executing synchronized instance method.");try {Thread.sleep(1000); // 模擬工作負載} catch (InterruptedException e) {e.printStackTrace();}}
}

2. synchronized 修飾靜態方法

與同步實例方法類似,但同步靜態方法鎖定的是類的Class對象,而不是某個特定的對象實例。這意味著對于整個類的所有實例,同一時間只能有一個線程執行該靜態同步方法。

public class SynchronizedExample {public static synchronized void synchronizedStaticMethod() {// 同步代碼塊System.out.println(Thread.currentThread().getName() + " is executing synchronized static method.");try {Thread.sleep(1000); // 模擬工作負載} catch (InterruptedException e) {e.printStackTrace();}}
}

synchronizedStaticMethod方法是靜態同步的,所以無論哪個實例調用了這個方法,都會鎖定該類的Class對象。

3. synchronized 修飾代碼塊

有時你可能不想同步整個方法,而是只同步其中的一部分代碼。這時可以使用同步代碼塊,它可以指定要鎖定的對象。

public class SynchronizedExample {private final Object lock = new Object();public void someMethod() {synchronized(lock) {// 需要同步的代碼塊System.out.println(Thread.currentThread().getName() + " is executing synchronized block.");try {Thread.sleep(1000); // 模擬工作負載} catch (InterruptedException e) {e.printStackTrace();}}}
}

在這個例子中,我們定義了一個私有的lock對象,并在需要同步的代碼塊周圍使用了synchronized(lock)。這種方式允許更細粒度地控制哪些代碼需要同步,同時減少了不必要的同步開銷。


二、Java對象結構

學習Java對象結構時,需要有 JVM的相關知識作為背景。

Java對象(Object實例)結構包括三部分:對象頭對象體對齊字節

1. 對象頭

對象頭包括三個字段:
  • Mark Word(標記字):用于存儲自身運行時的數據例,如GC標志位、哈希碼、鎖狀態等信息。
  • Class Pointer(類對象指針):用于存放此對象的元數據(InstanceKlass)的地址。虛擬機通過此指針可以確定這個對象是哪個類的實例。
  • Array Length(數組長度):如果對象是一個Java數組,那么此字段必須有,用于記錄數組長度的數據;如果對象不是一個Java數組,那么此字段不存在,所以這是一個可選字段。
    在這里插入圖片描述

2. 對象體

對象體包含了對象的實例變量(成員變量),用于成員屬性值,包括父類的成員屬性值。這部分內存按4字節對齊。

3. 對齊字節

對齊字節也叫作填充對齊,其作用是用來保證Java對象在所占內存字節數為8的倍數(8N bytes)。

并不是必然存在的,也沒有特別的含義,它僅僅起著占位符的作用。當對象實例數據部分沒有對齊(8字節的整數倍)時,就需要通過對齊填充來補全。

HotSpot VM的內存管理要求對象起始地址必須是8字節的整數倍。對象頭本身是8的倍數,當對象的實例變量數據不是8的倍數,需要填充數據來保證8字節的對齊。

4. 對象頭中的字段長度

Mark WordClass PointerArray Length字段的長度都為JVM的一個Word(字)大小。

在32位JVM虛擬機中,字段長度都是是32位的;在64位JVM虛擬機中,字段長度都是64位的。

對于對象指針而言,如果JVM中對象數量過多,使用64位的指針將浪費大量內存。通過簡單統計,64位的JVM將會比32位的JVM多耗費50%的內存。

為了節約內存可以使用選項+UseCompressedOops開啟指針壓縮。選項UseCompressedOops中的Oop部分為Ordinary object pointer(普通對象指針)的縮寫。

如果開啟UseCompressedOops選項,以下類型的指針將從64位壓縮至32位:

  • Class對象的屬性指針(即靜態變量)。
  • Object對象的屬性指針(即成員變量)。
  • 普通對象數組的元素指針。

當然,也不是所有的指針都會壓縮,一些特殊類型的指針不會壓縮,比如指向PermGen(永久代)的Class對象指針(JDK 8中指向元空間的Class對象指針)、本地變量、堆棧元素、入參、返回值和NULL指針等。

Mark Word的位長度不會受到OOP對象指針壓縮選項的影響。

在堆內存小于32GB的情況下,64位虛擬機的UseCompressedOops選項是默認開啟的,該選項表示開啟Oop對象的指針壓縮,會將原來64位的Oop對象指針壓縮為32位。

  • 手動開啟Oop對象指針壓縮的Java指令為:java -XX:+UseCompressedOops mainclass
  • 手動關閉Oop對象指針壓縮的Java指令為:java -XX:-UseCompressedOops mainclass

5. Mark Word 的結構信息

Java內置鎖的涉及很多重要信息,這些都存放在對象結構中,并且存放于對象頭的Mark Word字段中。Mark Word的位長度為JVM的一個Word大小,也就是說32位JVM的Mark Word為32位,4位JVM的Mark Word為64位。

Java內置鎖的狀態總共有4種,級別由低到高依次為:無鎖偏向鎖輕量級鎖重量級鎖

其實在JDK 1.6之前,Java內置鎖還是一個重量級鎖,是一個效率比較低下的鎖。

在JDK 1.6之后,JVM為了提高鎖的獲取與釋放效率,對synchronized的實現進行了優化,引入了偏向鎖、輕量級鎖的實現,從此以后Java內置鎖的狀態就有了4種(無鎖偏向鎖輕量級鎖重量級鎖),并且這4種狀態會隨著競爭的情況逐漸升級,而且是不可逆的過程,即不可降級,也就是說只能進行鎖升級(從低級別到高級別)。

1. 不同鎖狀態下的 Mark Word 字段結構

Mark Word字段的結構與Java內置鎖的狀態強相關。為了讓Mark Word字段存儲更多的信息,JVM將Mark Word的最低兩個位設置為Java內置鎖狀態位,不同鎖狀態下的32位Mark Word結構:

在這里插入圖片描述

64位的Mark Word與32位的Mark Word結構相似:

在這里插入圖片描述

2. 64 位 Mark Word 的構成

由于目前主流的JVM都是64位,使用64位的Mark Word,接下來對64位的Mark Word中各部分的內容做具體介紹。

  • lock:鎖狀態標記位,占兩個二進制位,由于希望用盡可能少的二進制位表示盡可能多的信息,所以設置了lock標記。該標記的值不同,整個Mark Word表示的含義不同。
  • biased_lock:對象是否啟用偏向鎖標記,只占1個二進制位。為1時表示對象啟用偏向鎖,為0時表示對象沒有偏向鎖。

lockbiased_lock兩個標記位組合在一起,共同表示 Object實例處于什么樣的鎖狀態。二者組合的含義如下:
在這里插入圖片描述

  • age:4位的Java對象分代年齡。在GC中,如果對象在Survivor區復制一次,年齡增加1。當對象達到設定的閾值時,將會晉升到老年代。默認情況下,并行GC的年齡閾值為15,并發GC的年齡閾值為6。由于age只有4位,因此最大值為15,這就是-XX:MaxTenuringThreshold選項最大值為15的原因。

  • identity_hashcode:31位的對象標識HashCode(哈希碼)采用延遲加載技術,當調用Object.hashCode()方法或者System.identityHashCode()方法計算對象的HashCode后,其結果將被寫到該對象頭中。當對象被鎖定時,該值會移動到Monitor(監視器)中。

  • thread:54位的線程ID值為持有偏向鎖的線程ID。

  • epoch:偏向時間戳。

  • ptr_to_lock_record:占62位,在輕量級鎖的狀態下指向棧幀中鎖記錄的指針。

  • ptr_to_heavyweight_monitor:占62位,在重量級鎖的狀態下,指向對象監視器的指針。

32位的Mark Word與64位Mark Word結構相似,這里不再贅述。

6. 使用 JOL 工具查看對象的布局


三、Java 內置鎖機制

3.1 內置鎖的演進過程

在JDK 1.6版本之前,所有的Java內置鎖都是重量級鎖。重量級鎖會造成CPU在用戶態和核心態之間頻繁切換,所以代價高、效率低。

JDK 1.6版本為了減少獲得鎖和釋放鎖所帶來的性能消耗,引入了“偏向鎖”和“輕量級鎖”實現。所以,在JDK 1.6版本里內置鎖一共有4種狀態:無鎖狀態偏向鎖狀態輕量級鎖狀態重量級鎖狀態,這些狀態隨著競爭情況逐漸升級。內置鎖可以升級但不能降級,意味著偏向鎖升級成輕量級鎖后不能降級成偏向鎖。這種能升級卻不能降級的策略,其目的是為了提高獲得鎖和釋放鎖的效率。

1. 無鎖狀態

當一個對象剛剛創建時,它處于無鎖狀態(也稱為自由狀態)。這意味著沒有任何線程試圖獲取該對象的鎖,因此可以認為它是自由訪問的。偏向鎖標識位是0、鎖狀態01。無鎖狀態下對象的Mark Word如下:
在這里插入圖片描述

2. 偏向鎖狀態

偏向鎖是JVM的一種優化技術,主要針對鎖只會被單個線程持有的場景。它的核心思想是假設鎖總是由同一個線程獲得,從而避免每次進入同步塊時都進行昂貴的原子操作(如CAS操作)。
【重點】

  • “偏向”:指的是內置鎖會偏向于當前已經占有過自己的線程。
  • 無鎖轉變為偏向鎖的過程:
    1. 無鎖轉向偏向鎖 :當線程A第一次嘗試獲取內置鎖時,如果此時對象處于無鎖狀態,并且沒有其他線程競爭該鎖,則JVM會將該對象的鎖狀態從無鎖轉變為偏向鎖。在轉變為偏向鎖的過程中,JVM會在對象頭中標記該鎖為偏向鎖,并記錄下持有該鎖的線程ID。
    2. 嘗試獲取偏向鎖線程A再次嘗試獲取該內置鎖時,可以直接進入,無需執行任何同步操作,因為系統“偏向”了這個線程。
    3. 撤銷偏向鎖:在線程 A第二次獲取內置鎖之前,線程 B 嘗試獲取該內置鎖,那么當前的偏向鎖會被撤銷,轉而升級為輕量級鎖或者根據競爭情況進一步升級為重量級鎖。
  • 原理:如果不存在線程競爭的一個線程獲得了鎖,那么鎖就進入偏向狀態,此時Mark Word的結構變為偏向鎖結構,鎖對象的鎖標志位(lock)被改為01,偏向標志位(biased_lock)被改為1,然后線程的ID記錄在鎖對象的Mark Word中(使用CAS操作完成)。以后該線程獲取鎖的時候判斷一下線程ID和標志位,就可以直接進入同步塊,連CAS操作都不需要,這樣就省去了大量有關鎖申請的操作,從而也就提升了程序的性能。

偏向鎖狀態下對象的Mark Word具體如下:
在這里插入圖片描述

3. 輕量級鎖狀態

  • 當鎖處于偏向鎖狀態,但是鎖又被另一個線程所企圖搶占時,偏向鎖就會升級為輕量級鎖。企圖搶占的線程會通過自旋的形式嘗試獲取鎖,不會阻塞搶鎖線程,以便提高性能。
  • 兩個線程公平競爭,哪個線程先占有鎖對象,鎖對象的Mark Word就指向哪個線程的棧幀中的鎖記錄。

輕量級鎖狀態下對象的Mark Word如圖所示:
在這里插入圖片描述

自旋的基本思想是讓一個線程不斷地檢查某個條件是否滿足,而不是直接進入阻塞狀態。

如果持有鎖的線程能在很短時間內釋放鎖資源,那么那些等待競爭鎖的線程就不需要做內核態和用戶態之間的切換進入阻塞掛起狀態,它們只需要不斷地檢查某個條件是否滿足,等持有鎖的線程釋放鎖后即可立即獲取鎖,這樣就避免用戶線程和內核切換的消耗。

但是,線程自旋是需要消耗 CPU的,如果一直獲取不到鎖,則線程也不能一直占用CPU自旋做無用功,所以需要設定一個自旋等待的最大時間。

輕量級鎖主要有兩種:普通自旋鎖自適應自旋鎖

普通自旋鎖

所謂普通自旋鎖,就是指當有線程來競爭鎖時,搶鎖線程會在原地循環等待,而不是被阻塞,直到那個占有鎖的線程釋放鎖之后,這個搶鎖線程才可以獲得鎖。

默認情況下,自旋的次數為10次,用戶可以通過-XX:PreBlockSpin選項來進行更改。

自適應自旋鎖

所謂自適應自旋鎖,就是等待線程空循環的自旋次數并非是固定的,而是會動態地根據實際情況來改變自旋等待的次數,自旋次數由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀態來決定。

自適應自旋鎖的大概原理是:

  • 如果搶鎖線程在同一個鎖對象上之前成功獲得過鎖,那么JVM就會認為這次自旋也很有可能再次成功,因此允許自旋等待持續相對更長的時間。

  • 如果對于某個鎖,搶鎖線程在很少成功獲得過,那么JVM將可能減少自旋時間甚至省略自旋過程,以避免浪費處理器資源。

自適應自旋解決的是“鎖競爭時間不確定”的問題。自適應自旋假定不同線程持有同一個鎖對象的時間基本相當,競爭程度趨于穩定。總的思想是:根據上一次自旋的時間與結果調整下一次自旋的時間。

JDK 1.6的輕量級鎖使用的是普通自旋鎖,且需要使用-XX:+UseSpinning選項手工開啟。

JDK 1.7后,輕量級鎖使用自適應自旋鎖,JVM啟動時自動開啟,且自旋時間由JVM自動控制。

4. 重量級鎖狀態

重量級鎖會讓其他申請的線程之間進入阻塞,性能降低。重量級鎖也就叫同步鎖,這個鎖對象Mark Word再次發生變化,會指向一個監視器對象,該監視器對象用集合的形式來登記和管理排隊的線程。重量級鎖狀態下對象的Mark Word具體

在JVM中,每個對象都關聯一個監視器,這里的對象包含了Object實例和Class實例。監視器是一個同步工具,相當于一個許可證,拿到許可證的線程即可以進入臨界區進行操作,沒有拿到則需要阻塞等待。重量級鎖通過監視器的方式保障了任何時間只允許一個線程通過受到監視器保護的臨界區代碼。

核心原理

JVM中每個對象都會有一個監視器,監視器和對象一起創建、銷毀。監視器相當于一個用來監視這些線程進入的特殊房間,其義務是保證(同一時間)只有一個線程可以訪問被保護的臨界區代碼塊。

本質上,監視器是一種同步工具,也可以說是一種同步機制,主要特點是:

  • 同步。監視器所保護的臨界區代碼是互斥地執行的。一個監視器是一個運行許可,任一個線程進入臨界區代碼都需要獲得這個許可,離開時把許可歸還。

  • 協作。監視器提供Signal機制,允許正持有許可的線程暫時放棄許可進入阻塞等待狀態,等待其他線程發送Signal去喚醒;其他擁有許可的線程可以發送Signal,喚醒正在阻塞等待的線程,讓它可以重新獲得許可并啟動執行。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/73524.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/73524.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/73524.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LLM(3): Transformer 架構

Transformer 架構是當前大語言模型的主力架構和基礎技術,本文以通俗易懂的方式,對此作簡要介紹。 1.4 介紹 Transformer 架構 大多數現代的大規模語言模型(LLMs)依賴于 Transformer 架構,這是一種在 2017 年的論文《…

11.【.NET 8 實戰--孢子記賬--從單體到微服務--轉向微服務】--微服務基礎工具與技術--Ocelot 網關--整合日志

網關作為微服務架構的入口,承載著各服務間的請求轉發與安全校驗,其日志信息尤為關鍵。通過整合網關日志,可以將分散在不同系統中的訪問記錄、錯誤提示和異常信息集中管理,為問題排查提供全景視角。在排查故障時,統一日…

88.HarmonyOS NEXT 性能監控與調試指南:構建高性能應用

溫馨提示:本篇博客的詳細代碼已發布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下載運行哦! HarmonyOS NEXT 性能監控與調試指南:構建高性能應用 文章目錄 HarmonyOS NEXT 性能監控與調試指南:構建高性能應用1. 性能監…

012---狀態機的基本知識

1. 摘要 文章為學習記錄。主要介紹狀態機概述、狀態轉移圖、狀態編碼、狀態機寫法、狀態機代碼示例。 2. 狀態機概述 狀態機 (Finite State Machine),也稱為同步有限狀態機,用于描述有先后順序或時序規律的事情。 “同步”&…

deepseek+kimi做ppt教程記錄

1.首先注冊deepseek和kimi deepseek官網:https://chat.deepseek.com/ kimi官網:https://kimi.moonshot.cn/ 以下以一篇工作總結報告為例 2.使用deepseek生成ppt大綱 讓deepseek生成kimi生成ppt所需要的內容時,需要注意提示詞內容,…

Java Module介紹

Java模塊系統自Java 9開始引入,旨在提供更強大的封裝機制、清晰的依賴關系定義以及可靠的配置。Java平臺本身也被模塊化了,提供了多個核心模塊以及其他用于支持不同功能的模塊。以下是一些重要的Java標準模塊: java.base - 這是最基礎的模塊…

SOME/IP:用Python實現協議訂閱、Offer、訂閱ACK與報文接收

文章目錄 前言一、代碼層次二、詳細代碼1. eth_scapy_sd.py2、eth_scapy_someip.py3、network_define.py4、packet_define.py5、unpack_define.py6、someip_controller.py 前言 1、需要pip安裝scapy庫 2、需要修改根據實際情況配置network_define.py 3、執行someip_controller…

【Linux內核系列】:文件系統收尾以及軟硬鏈接詳解

🔥 本文專欄:Linux 🌸作者主頁:努力努力再努力wz 💪 今日博客勵志語錄: 世界上只有一種個人英雄主義,那么就是面對生活的種種失敗卻依然熱愛著生活 內容回顧 那么在之前的學習中,我們…

最新版Chrome瀏覽器加載ActiveX控件技術--allWebPlugin中間件一鍵部署瀏覽器擴展

allWebPlugin簡介 allWebPlugin中間件是一款為用戶提供安全、可靠、便捷的瀏覽器插件服務的中間件產品,致力于將瀏覽器插件重新應用到所有瀏覽器。它將現有ActiveX控件直接嵌入瀏覽器,實現插件加載、界面顯示、接口調用、事件回調等。支持Chrome、Firefo…

基于SpringBoot和MybatisPlus實現通用Controller

基于SpringBoot和MybatisPlus實現通用Controller,只需要創建實體類和mapper接口,單表增刪改查接口就已經實現,提升開發效率 1.定義通用controller package com.xian.controller;import cn.hutool.core.map.MapUtil; import com.baomidou.my…

Axure大屏可視化原型模板及素材:數據可視化的高效解決方案

數據可視化已成為企業決策、運營分析、市場洞察的重要工具。數據可視化大屏,作為數據展示和交互的直觀平臺,能夠實時呈現關鍵數據,幫助企業快速做出決策。Axure作為原型設計領域的領先工具,以其豐富的組件庫、強大的交互設計能力和…

YOLOE:實時查看任何事物

摘要 https://arxiv.org/pdf/2503.07465v1 目標檢測和分割在計算機視覺應用中得到了廣泛應用,然而,盡管YOLO系列等傳統模型高效且準確,但它們受限于預定義的類別,阻礙了在開放場景中的適應性。最近的開放集方法利用文本提示、視覺…

【品鉑科技工業生產應用案例解析】

品鉑科技(Pinpoint)在工業領域的高精度定位解決方案已廣泛應用于電力、鋼鐵、倉儲、化工、地鐵等場景,以下為典型應用案例及技術方案: 一、?電力行業:上海閔行電廠人員定位? 白鶴灘水力發電站 ?項目需求?&#x…

7-Zip 功能介紹

7-Zip 是一款開源、高效的文件壓縮與解壓縮工具,支持多種格式,以高壓縮率和靈活性著稱。以下是其核心功能: 多格式支持 壓縮 / 解壓:支持 7z(默認格式,壓縮率極高)、ZIP、RAR、GZIP、BZIP2、TAR…

這是我第一次寫關於aapenal服務器管理控制面板的文章

首先我們來認識一下服務器管理面板的所有功能 ? 網站管理功能: 支持創建和管理多個網站。配置虛擬主機(Vhost)和域名綁定。自動安裝常用應用(如WordPress、Joomla等)。 ? 文件管理功能: 文件上傳、…

小語言模型(SLM)技術解析:如何在有限資源下實現高效AI推理

引言:為什么小語言模型(SLM)是2025年的技術焦點? 2025年,人工智能領域正經歷一場“由大變小”的革命。盡管大語言模型(LLM)如GPT-4、Gemini Ultra等在復雜任務中表現驚艷,但其高昂的…

jmeter:登錄接口的token用于下一個接口

問題: 僅僅登錄接口可以使用,其他接口進行測試的時候都是報錯:賬號已經失效 原因: 應該是登錄接口的token并沒有用到下一個接口上來 解決方法 1、目錄建設如下: 2、先添加一個后置處理器:查看結果數&…

1、操作系統引論

一、操作系統 會使用linux系統 建議大家先學會linux的基礎指令,可以看菜鳥教程網站進行學習。 1、各種定義 操作系統定義 管理計算機的 硬件 和軟件資源, 能對各類作業進行調度,方便用戶使用計算機的程序集合。操作系統運行在內核態&#xf…

KVM安全模塊生產環境配置與優化指南

KVM安全模塊生產環境配置與優化指南 一、引言 在當今復雜多變的網絡安全環境下,生產環境中KVM(Kernel-based Virtual Machine)的安全配置顯得尤為重要。本指南旨在詳細闡述KVM安全模塊的配置方法,結合強制訪問控制(M…

深入解析工廠模式及其C#實現

工廠模式(Factory Pattern)是設計模式中的一種創建型模式,它通過工廠方法來創建對象,而不是讓客戶端代碼直接實例化對象。這樣可以避免客戶端與具體類的緊密耦合,從而提高代碼的靈活性、可維護性和擴展性。工廠模式能夠…