線程池(二):深入剖析synchronized關鍵字的底層原理

線程池(二):深入剖析synchronized關鍵字的底層原理

  • 線程池(二):深入剖析`synchronized`關鍵字的底層原理
    • 一、基本使用
      • 1.1 修飾實例方法
      • 1.2 修飾靜態方法
      • 1.3 修飾代碼塊
    • 二、Monitor
      • 2.1 Monitor的概念
      • 2.2 Monitor的實現原理
      • 2.3 Monitor與`synchronized`的關系
    • 三、synchronized關鍵字的底層原理 - 進階
      • 3.1 對象的內存結構
      • 3.2 MarkWord
      • 3.3 再說Monitor重量級鎖
      • 3.4 輕量級鎖
      • 3.5 偏向鎖
      • 3.6 談談JMM(Java內存模型)

線程池(二):深入剖析synchronized關鍵字的底層原理

一、基本使用

1.1 修飾實例方法

synchronized修飾一個實例方法時,它鎖定的是當前對象(this)。例如:

public class SynchronizedExample {public synchronized void synchronizedMethod() {// 同步代碼塊// 同一時刻,只有一個線程能進入這個方法}
}

在上述代碼中,任何線程在調用synchronizedMethod方法時,都需要獲取當前對象的鎖。如果一個線程已經持有了這個鎖,其他線程就需要等待,直到該線程釋放鎖。

1.2 修飾靜態方法

synchronized修飾靜態方法時,它鎖定的是當前類的Class對象。因為靜態方法屬于類,而不是某個具體的實例。示例如下:

public class StaticSynchronizedExample {public static synchronized void staticSynchronizedMethod() {// 同步代碼塊// 同一時刻,只有一個線程能進入這個靜態方法}
}

不管有多少個該類的實例,對于這個靜態同步方法,同一時刻只有一個線程可以執行。這是因為所有線程共享類的Class對象,鎖的就是這個唯一的Class對象。

1.3 修飾代碼塊

synchronized還可以修飾代碼塊,這種方式更加靈活,可以指定具體要鎖定的對象。例如:

public class SynchronizedBlockExample {private final Object lock = new Object();public void someMethod() {synchronized (lock) {// 同步代碼塊// 同一時刻,只有一個線程能進入這個代碼塊}}
}

這里通過synchronized (lock)指定了鎖定的對象是lock。當多個線程同時訪問someMethod方法時,只有一個線程能獲取到lock對象的鎖并執行同步代碼塊中的內容。

二、Monitor

2.1 Monitor的概念

Monitor(監視器)是Java并發編程中實現同步的一個核心概念。它可以理解為一個同步工具,也可以說是一種同步機制。每個Java對象都可以關聯一個Monitor。當一個線程想要進入同步代碼塊(無論是synchronized修飾的方法還是代碼塊)時,它需要先獲取對應的Monitor。

2.2 Monitor的實現原理

在HotSpot虛擬機中,Monitor是由ObjectMonitor結構體實現的。它主要包含以下幾個關鍵部分:

  • header:對象頭,用于存儲對象的一些元數據信息,比如對象的哈希碼、對象的分代年齡等。
  • count:記錄該Monitor被獲取的次數。當一個線程成功獲取到Monitor后,_count會加1,每次釋放鎖時,_count會減1。當_count為0時,代表該Monitor沒有被任何線程持有。
  • owner:指向當前持有該Monitor的線程。如果當前沒有線程持有該Monitor,_ownernull
  • WaitSet:等待隊列,當線程調用對象的wait()方法時,該線程會被放入這個等待隊列中,進入等待狀態。
  • EntryList:入口隊列,當多個線程同時競爭一個Monitor時,沒有獲取到鎖的線程會被放入這個入口隊列中等待。

2.3 Monitor與synchronized的關系

synchronized關鍵字的底層實現依賴于Monitor。當一個線程進入synchronized修飾的同步代碼塊或方法時,實際上就是去獲取對應的Monitor。如果獲取成功,就可以執行同步代碼;如果獲取失敗,就會被放入EntryList隊列中等待。當持有鎖的線程執行完同步代碼或者調用wait()方法時,會釋放Monitor,此時會從EntryList隊列中喚醒一個等待的線程來獲取Monitor。

三、synchronized關鍵字的底層原理 - 進階

3.1 對象的內存結構

在Java中,對象在內存中的布局主要包括三個部分:對象頭(Header)、實例數據(Instance Data)和對齊填充(Padding)。

  • 對象頭(Header):對象頭又分為兩部分,一部分是用于存儲對象自身的運行時數據,比如哈希碼(HashCode)、對象的分代年齡、鎖標志位等,這部分數據被稱為MarkWord;另一部分是指向對象所屬類的Class對象的指針,用于確定對象的類型。
  • 實例數據(Instance Data):這部分用于存儲對象的成員變量,包括從父類繼承下來的成員變量和本類定義的成員變量。
  • 對齊填充(Padding):由于虛擬機要求對象的起始地址必須是8字節的整數倍,所以當對象頭和實例數據部分的總大小不是8字節的整數倍時,需要通過對齊填充來補足。

3.2 MarkWord

MarkWord是對象頭中非常重要的一部分,它在不同的鎖狀態下會存儲不同的信息。在32位虛擬機中,MarkWord的長度是32位(4個字節),在64位虛擬機中,MarkWord的長度是64位(8個字節)。以下是不同鎖狀態下MarkWord的存儲內容:

  • 無鎖狀態:在無鎖狀態下,MarkWord存儲對象的哈希碼、對象的分代年齡等信息。例如在32位虛擬機中,前25位存儲對象的哈希碼,后4位存儲對象的分代年齡,最后3位是鎖標志位(01表示無鎖)。
  • 偏向鎖狀態:當對象進入偏向鎖狀態時,MarkWord中會存儲持有該鎖的線程ID等信息。
  • 輕量級鎖狀態:在輕量級鎖狀態下,MarkWord會存儲指向棧幀中鎖記錄的指針。
  • 重量級鎖狀態:當對象處于重量級鎖狀態時,MarkWord會存儲指向Monitor對象的指針。

3.3 再說Monitor重量級鎖

當多個線程競爭同一個鎖,且競爭比較激烈時,輕量級鎖會升級為重量級鎖。此時,MarkWord中存儲的是指向ObjectMonitor的指針。重量級鎖是通過操作系統的互斥量(Mutex)來實現的,線程獲取和釋放鎖都需要進行用戶態和內核態的切換,這種切換開銷比較大。

當一個線程進入synchronized同步代碼塊時,如果發現是重量級鎖,它會進入ObjectMonitorEntryList隊列中等待。持有鎖的線程執行完同步代碼后,會釋放鎖,然后從EntryList隊列中喚醒一個等待的線程。被喚醒的線程會再次嘗試獲取鎖,獲取成功后才能執行同步代碼。

3.4 輕量級鎖

輕量級鎖是為了在沒有多線程競爭或者競爭不激烈的情況下,減少獲取鎖和釋放鎖的開銷而引入的。當一個線程進入synchronized同步代碼塊時,會在當前線程的棧幀中創建一個鎖記錄(Lock Record),并將MarkWord復制到鎖記錄中。然后,線程嘗試通過CAS(Compare and Swap,比較并交換)操作將MarkWord更新為指向鎖記錄的指針。如果CAS操作成功,說明該線程獲取到了輕量級鎖,就可以執行同步代碼。

如果CAS操作失敗,說明有其他線程已經持有了該鎖,此時輕量級鎖會嘗試自旋(Spin)一定次數來等待鎖的釋放。自旋是指線程不放棄CPU的執行權,在原地等待一段時間,希望持有鎖的線程能盡快釋放鎖。如果自旋一定次數后仍然沒有獲取到鎖,輕量級鎖就會升級為重量級鎖。

3.5 偏向鎖

偏向鎖是在JDK 6中引入的,它的目的是為了在只有一個線程訪問同步代碼塊的情況下,進一步減少獲取鎖的開銷。當一個線程訪問synchronized同步代碼塊時,會檢查MarkWord中是否已經記錄了該線程的ID。如果已經記錄,說明該線程已經持有了偏向鎖,直接進入同步代碼塊執行。

如果MarkWord中沒有記錄該線程的ID,會通過CAS操作將線程ID記錄到MarkWord中。如果CAS操作成功,就表示該線程獲取到了偏向鎖。當有其他線程嘗試獲取該鎖時,偏向鎖會被撤銷,升級為輕量級鎖。

3.6 談談JMM(Java內存模型)

Java內存模型(JMM)定義了Java程序中多線程訪問共享變量的規則。它規定了一個線程如何和何時可以看到由其他線程修改過后的共享變量的值,以及在必須時如何同步的訪問共享變量。

synchronized關鍵字的實現中,JMM起到了重要的作用。當一個線程獲取到鎖進入synchronized同步代碼塊時,會從主內存中讀取共享變量的值到工作內存中。在同步代碼塊執行過程中,對共享變量的修改會先在工作內存中進行。當線程執行完同步代碼塊釋放鎖時,會將工作內存中修改后的共享變量的值寫回到主內存中。這樣可以保證在同一時刻,只有一個線程能夠對共享變量進行修改,并且其他線程能夠看到最新的修改結果,從而保證了多線程環境下共享變量的可見性和一致性。

通過對synchronized關鍵字從基本使用到深入底層原理的剖析,包括Monitor機制、對象內存結構、不同鎖狀態以及與Java內存模型的關系等方面,我們對synchronized在Java并發編程中的作用和實現有了一個全面而深入的理解。這有助于我們在實際開發中更合理、高效地使用synchronized來解決多線程同步問題。

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

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

相關文章

Linux CentOS 7 安裝Apache 部署html頁面

*、使用yum包管理器安裝Apache。運行以下命令: sudo yum install httpd *、啟動Apache服務 sudo systemctl start httpd *、設置Apache服務開機自啟 # 啟用開機自啟動 sudo systemctl enable httpd# 禁用開機自啟動 sudo systemctl disable httpd *、驗證Apac…

前端設置三行文本省略號,失效為什么?

實際效果:第三行出現省略號,但是第四行依舊顯示了部分文字 這個問題通常是由于 CSS 多行文本截斷(-webkit-line-clamp)的計算方式或布局沖突導致的。以下是完整解決方案,確保三行文本截斷正確顯示省略號,并…

git學習之git常用命令

1. 初始化倉庫 git init初始化一個新的 Git 倉庫。 2. 克隆遠程倉庫 git clone <repository-url>從遠程服務器克隆一個已有倉庫到本地。 3. 配置用戶名和郵箱 git config --global user.name "Your Name" git config --global user.email "youexampl…

【Spring Boot】深入解析:#{} 和 ${}

1.#{} 和 ${}的使用 1.1數據準備 1.1.1.MySQL數據準備 &#xff08;1&#xff09;創建數據庫&#xff1a; CREATE DATABASE mybatis_study DEFAULT CHARACTER SET utf8mb4;&#xff08;2&#xff09;使用數據庫 -- 使?數據數據 USE mybatis_study;&#xff08;3&#xff…

Poco C++全面開發指南:日期和時間

時間戳 時間戳是指格林威治時間1970年01月01日00時00分00秒&#xff08;北京時間1970年01月01日08時00分00秒&#xff09;起至現在的總秒數。在poco中可以可以使用Timestamp類獲取。 #include <Poco/Timestamp.h> #include <iostream>int main() {Poco::Timestam…

水利三維可視化平臺怎么做?快速上手的3步指南

分享大綱&#xff1a; 1、了解水利三維可視化平臺 2、選擇合適的開發平臺 3、快速搭建水利三維可視化平臺 第一步&#xff1a;了解水利三維可視化平臺 水利三維可視化平臺是利用大數據、物聯網、數字孿生等技術&#xff0c;將物理實體數字化建模&#xff0c;并通過三維可視化技…

高級前端面試題:基于2025年最新技術體系

高級前端面試題:基于2025年最新技術體系 引言 隨著前端技術的不斷發展,2025年的前端面試題也呈現出新的特點和趨勢。本報告基于最新的前端技術體系,收集了當前熱門的面試題,旨在幫助準備高級前端工程師面試的候選人全面了解面試考察點。報告內容涵蓋HTML5 Canvas、WebGL、…

圖像處理——邊緣檢測

1 概述 邊緣檢測是圖像處理和計算機視覺中的一項基本技術&#xff0c;用于識別圖像中亮度變化劇烈的像素點&#xff0c;這些像素點通常對應于物體的邊界。它通過檢測圖像中亮度或顏色變化顯著的區域&#xff0c;提取出物體的輪廓&#xff0c;常用于計算機視覺、圖像處理和模式識…

c語言的常用的預處理指令和條件編譯

c語言的常用的預處理指令和條件編譯 預處理詳解預定義符號#define#define 定義標識符#define 定義宏帶副作用的宏參數宏和函數的對比#define命名約定和#undef移除宏 # 和 ## 參數插入字符串字符串的自動連接#宏參數 命令行定義條件編譯#if和#endif多分支條件編譯#if、#elif、#e…

TTL、RS-232 和 RS-485 串行通信電平標準區別解析

TTL、RS-232 和 RS-485 是三種常見的串行通信電平標準&#xff0c;它們各自有不同的協議特點&#xff0c;適用于不同的應用場景。以下是它們的主要特點對比&#xff1a; ??1. TTL&#xff08;Transistor-Transistor Logic&#xff09;?? ??主要特點?? ??單端信號?…

SwinTransformer改進(6):與Dual Cross-Attention結合的視覺模型

在計算機視覺領域,Transformer架構正逐漸取代傳統的CNN成為主流。 本文將深入解析一個結合了Swin Transformer和Dual Cross-Attention(DCA)的創新模型實現。 模型概述 這個實現的核心是將Swin Transformer(一種高效的視覺Transformer)與創新的Dual Cross-Attention模塊相結…

Dify框架面試內容整理-Dify框架

什么是Dify框架? Dify框架是一個開源的AI應用開發平臺,專注于幫助開發者和非技術人員快速構建、部署和管理基于大語言模型(如GPT系列、國產開源模型)的應用。 Dify框架的特點:

道可云人工智能每日資訊|“人工智能科技體驗展”在中國科學技術館舉行

道可云元宇宙每日簡報&#xff08;2025年4月28日&#xff09;訊&#xff0c;今日元宇宙新鮮事有&#xff1a; 《2025年提升全民數字素養與技能工作要點》發布 近日&#xff0c;中央網信辦、教育部、工業和信息化部、人力資源社會保障部聯合印發《2025年提升全民數字素養與技能…

基于javaweb的SpringBoot新聞發布系統設計與實現(源碼+文檔+部署講解)

技術范圍&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、小程序、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容&#xff1a;免費功能設計、開題報告、任務書、中期檢查PPT、系統功能實現、代碼編寫、論文編寫和輔導、論文…

蒼穹外賣心得體會

1 登錄認證 技術點&#xff1a;JWT令牌技術&#xff08;JSON Web Token&#xff09; JWT&#xff08;JSON Web Token&#xff09;是一種令牌技術&#xff0c;主要由三部分組成&#xff1a;Header頭部、Payload載荷和Signature簽名。Header頭部存儲令牌的類型&#xff08;如JW…

車載功能測試-車載域控/BCM控制器測試用例開發流程【用例導出方法+優先級劃分原則】

目錄 1 摘要2 位置燈手動控制簡述2.1 位置燈手動控制需求簡述2.2 位置燈手動控制邏輯交互圖 3 用例導出方法以及優先級原則3.1 用例導出方法3.1.1 用例導出方法介紹3.1.2 用例導出方法關鍵差異分析 3.2 優先級規則3.2.1 優先級劃分的核心原則3.2.2 具體等級定義與判定標準 3.3 …

Linux系統基礎:基礎指令簡介(網絡概念部分)

簡介&#xff1a;Linux 是一種開源的類 Unix 操作系統內核&#xff0c;由 Linus Torvalds 于 1991 年首次發布。經過多年發展&#xff0c;它已成為服務器、嵌入式設備和個人計算機領域的重要操作系統。 網絡基礎概念 初始協議 簡單來說&#xff0c;協議是一種約定&#xff0…

多模態(3):實戰 GPT-4o 視頻理解

最近&#xff0c;OpenAI 團隊的 GPT-4o 模型&#xff0c;在多模態方面的能力有了大幅提升&#xff0c;這次我們就使用 GPT-4o 完成一個視頻理解的實戰。 1. 環境搭建 1.1 安裝 FFmpeg 做視頻處理&#xff0c;我們需要用到 FFmpeg 這款功能強大的開源多媒體處理工具。FFmpeg…

(27)VTK C++開發示例 ---將點坐標寫入 STL文件

文章目錄 1. 概述2. CMake鏈接VTK3. main.cpp文件4. 演示效果 更多精彩內容&#x1f449;內容導航 &#x1f448;&#x1f449;VTK開發 &#x1f448; 1. 概述 此示例使用 vtkSTLWriter 將存儲在 vtkPolyData 對象中的 3D 幾何數據保存到 STL 文件&#xff0c;并讀取stl文件顯示…

2. python協程/異步編程詳解

目錄 1. 簡單的異步程序 2. 協程函數和協程對象 3. 事件循環 4. 任務對象Task及Future對象 4.1 Task與Future的關系 4.2 Future對象 4.3 全局對象和循環事件對象 5. await關鍵字 6. 異步上下文管理 7.異步迭代器 8. asyncio的常用函數 8.1 asyncio.run 8.2 asyncio.get…