【Synchronized】不同的使用場景和案例

【Synchronized】不同的使用場景和案例

  • 【一】鎖的作用范圍與鎖對象
    • 【1】實例方法(對象鎖)
    • 【2】靜態方法(類鎖)
    • 【3】代碼塊(顯式指定鎖對象)
    • 【4】類鎖(通過Class對象顯式鎖定)
  • 【二】核心區別總結
  • 【三】關鍵注意事項
    • 【1】內存可見性
    • 【2】避免死鎖
    • 【3】鎖粒度過大問題
  • 【四】測試案例補充
  • 【五】原理
    • 【1】Synchronized鎖原理
      • (1)對象頭
      • (2)監視器(Monitor)
      • (3)字節碼層面的實現
    • 【2】鎖升級原理
      • (1)無鎖狀態
      • (2)偏向鎖
      • (3)輕量級鎖
      • (4)重量級鎖
    • 【3】總結

【一】鎖的作用范圍與鎖對象

【1】實例方法(對象鎖)

(1)鎖對象:當前實例(this)。
(2)作用范圍:同一實例的多個線程訪問同步方法時互斥;不同實例的同步方法互不影響。
(3)測試案例:

public class BankAccount {private int balance = 1000;public synchronized void withdraw(int amount) {if (balance >= amount) {balance -= amount;}}
}// 測試代碼
BankAccount account1 = new BankAccount();
BankAccount account2 = new BankAccount();// 線程1操作account1的withdraw方法(互斥)
new Thread(() -> account1.withdraw(500)).start();
// 線程2操作account1的withdraw方法(被阻塞)
new Thread(() -> account1.withdraw(500)).start();
// 線程3操作account2的withdraw方法(不受影響)
new Thread(() -> account2.withdraw(500)).start();

(4)結果:線程1和線程2對account1的操作互斥;線程3與account1的操作無關

【2】靜態方法(類鎖)

(1)鎖對象:類的Class對象(如BankAccount.class)。
(2)作用范圍:所有實例調用靜態同步方法時互斥。
(3)測試案例:

public class OrderService {private static int orderCount = 0;public static synchronized void generateOrder() {orderCount++;}
}// 測試代碼
OrderService instanceA = new OrderService();
OrderService instanceB = new OrderService();// 線程1調用靜態方法(互斥)
new Thread(() -> OrderService.generateOrder()).start();
// 線程2調用靜態方法(被阻塞)
new Thread(() -> OrderService.generateOrder()).start();
// 線程3通過實例調用靜態方法(同樣被阻塞)
new Thread(() -> instanceA.generateOrder()).start();

(4)結果:所有線程調用generateOrder()都會競爭同一把類鎖,無論通過類名還是實例調用。

【3】代碼塊(顯式指定鎖對象)

(1)鎖對象:任意顯式指定的對象(如實例變量、類對象)。
(2)作用范圍:僅同步代碼塊內的操作,鎖粒度更細。
(3)測試案例:

public class CacheManager {private final Object lock = new Object();private int cacheSize = 0;public void updateCache() {// 非同步代碼System.out.println("非同步操作");synchronized(lock) { // 顯式鎖定lock對象cacheSize++;}}
}// 測試代碼
CacheManager manager = new CacheManager();
// 線程1和線程2競爭lock對象的鎖
new Thread(() -> manager.updateCache()).start();
new Thread(() -> manager.updateCache()).start();

(4)結果:僅代碼塊內的cacheSize++操作互斥,其他代碼可并發執行347。

【4】類鎖(通過Class對象顯式鎖定)

(1)鎖對象:類的Class對象(如ClassName.class)。
(2)作用范圍:與靜態方法鎖效果一致,但可用于非靜態方法中。
(3)測試案例:

public class LockDemo {public void classLockBlock() {synchronized(LockDemo.class) { // 顯式鎖定類對象// 同步代碼}}
}// 線程1和線程2調用classLockBlock方法時互斥
LockDemo obj1 = new LockDemo();
LockDemo obj2 = new LockDemo();
new Thread(() -> obj1.classLockBlock()).start();
new Thread(() -> obj2.classLockBlock()).start();

(4)結果:不同實例調用classLockBlock時仍互斥,因為鎖的是LockDemo.class

【二】核心區別總結

鎖類型 鎖對象 作用范圍 適用場景
實例方法(對象鎖) 當前實例(this) 同一實例的同步方法 保護實例變量(如賬戶余額)
靜態方法(類鎖) 類的Class對象 所有實例的靜態方法 保護靜態變量(如全局計數器)
顯式對象鎖 指定對象(如lock) 鎖定指定對象的同步代碼塊 細粒度控制(如緩存更新)
顯式類鎖 ClassName.class 跨實例同步(與靜態方法鎖等效) 需要全局同步的非靜態方法邏輯

【三】關鍵注意事項

【1】內存可見性

實例鎖僅保證同一實例內的變量可見性。
類鎖保證所有實例間的變量可見性(因Class對象在方法區共享)。

【2】避免死鎖

按固定順序獲取鎖(如先鎖A再鎖B)。
避免嵌套鎖(如synchronized方法內調用另一個synchronized方法時需謹慎)。

【3】鎖粒度過大問題

錯誤示例:將耗時操作(如IO)放在同步方法內。
優化方案:僅同步關鍵代碼塊

【四】測試案例補充

場景:對象鎖與類鎖的互斥性測試

public class MixedLockDemo {public synchronized void instanceMethod() {// 實例鎖}public static synchronized void staticMethod() {// 類鎖}
}// 線程1調用實例方法,線程2調用靜態方法
MixedLockDemo obj = new MixedLockDemo();
new Thread(() -> obj.instanceMethod()).start();  // 鎖obj實例
new Thread(() -> MixedLockDemo.staticMethod()).start();  // 鎖MixedLockDemo.class

結果:兩個線程不會互斥,因為實例鎖和類鎖是獨立的

【五】原理

【1】Synchronized鎖原理

(1)對象頭

在 Java 中,每個對象都有一個對象頭(Object Header),對象頭中包含了一些與對象自身相關的信息,如哈希碼、分代年齡等,同時也包含了鎖的相關信息。對象頭的結構在不同的 JVM 實現中可能會有所不同,但通常會包含一個 Mark Word 字段,這個字段用于存儲對象的鎖狀態、哈希碼等信息。

(2)監視器(Monitor)

synchronized 關鍵字的底層實現依賴于監視器(Monitor)。監視器是 Java 中實現同步的基礎,它是一個同步工具,相當于一個特殊的房間,線程進入這個房間就相當于獲得了鎖,其他線程則需要等待。每個 Java 對象都可以關聯一個監視器,當一個線程試圖訪問被 synchronized 修飾的代碼塊或方法時,它會首先嘗試獲取該對象的監視器。

(3)字節碼層面的實現

當使用 synchronized 修飾代碼塊時,編譯后的字節碼會包含 monitorenter 和 monitorexit 指令。例如:

public class SynchronizedExample {public void test() {synchronized (this) {// 同步代碼塊}}
}

編譯后的字節碼中會包含如下指令:

monitorenter
// 同步代碼塊的字節碼
monitorexit

(1)monitorenter 指令
當線程執行到 monitorenter 指令時,它會嘗試獲取對象的監視器。如果監視器的進入計數器為 0,表示該監視器沒有被其他線程持有,當前線程可以獲取該監視器,并將進入計數器加 1。如果監視器已經被其他線程持有,當前線程會被阻塞,直到該監視器被釋放。

(2)monitorexit 指令
當線程執行到 monitorexit 指令時,它會將監視器的進入計數器減 1。當進入計數器為 0 時,表示當前線程已經釋放了該監視器,其他線程可以嘗試獲取該監視器。

當使用 synchronized 修飾方法時,編譯后的字節碼會在方法的訪問標志中設置 ACC_SYNCHRONIZED 標志。當線程調用該方法時,會自動檢查該標志,如果設置了該標志,線程會首先嘗試獲取該方法所屬對象的監視器,然后再執行方法體。

【2】鎖升級原理

在 Java 6 之前,synchronized 是一個重量級鎖,性能較低。為了提高性能,Java 6 引入了鎖升級機制,使得 synchronized 的性能有了顯著提升。鎖升級的過程是一個逐步升級的過程,從無鎖狀態開始,經過偏向鎖、輕量級鎖,最終升級為重量級鎖。

(1)無鎖狀態

對象剛被創建時,處于無鎖狀態,Mark Word 中存儲的是對象的哈希碼、分代年齡等信息。

(2)偏向鎖

(1)原理:偏向鎖是為了在沒有競爭的情況下減少鎖的獲取和釋放帶來的性能開銷。當一個線程第一次訪問被 synchronized 修飾的代碼塊或方法時,會在對象頭的 Mark Word 中記錄該線程的 ID,這個過程稱為偏向鎖的獲取。以后該線程再次進入該同步代碼塊時,無需進行任何同步操作,直接進入代碼塊執行,這樣可以避免頻繁的鎖獲取和釋放操作,提高性能。

(2)升級條件:當有其他線程嘗試競爭該偏向鎖時,偏向鎖會升級為輕量級鎖。

(3)輕量級鎖

(1)原理:當線程獲取輕量級鎖時,會在當前線程的棧幀中創建一個鎖記錄(Lock Record),并將對象頭的 Mark Word 復制到鎖記錄中。然后,線程嘗試使用 CAS(Compare-And-Swap)操作將對象頭的 Mark Word 替換為指向鎖記錄的指針。如果替換成功,說明該線程成功獲取了輕量級鎖;如果替換失敗,說明有其他線程正在競爭該鎖,當前線程會嘗試自旋等待鎖的釋放。

(2)升級條件:如果自旋次數達到一定閾值(通常由 JVM 動態調整),或者有多個線程同時競爭該鎖,輕量級鎖會升級為重量級鎖。

(4)重量級鎖

原理:重量級鎖依賴于操作系統的互斥量(Mutex)來實現,當線程獲取重量級鎖失敗時,會被阻塞,進入等待隊列,直到鎖被釋放。重量級鎖的性能開銷較大,因為線程的阻塞和喚醒需要操作系統進行上下文切換,這會消耗較多的 CPU 時間。

【3】總結

synchronized 鎖的實現原理基于對象頭和監視器,通過 monitorenter 和 monitorexit 指令或 ACC_SYNCHRONIZED 標志來實現線程同步。鎖升級原理是為了在不同的競爭情況下選擇合適的鎖狀態,以提高性能。在無競爭的情況下,使用偏向鎖;在有少量競爭的情況下,使用輕量級鎖;在競爭激烈的情況下,使用重量級鎖。

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

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

相關文章

大模型在原發性急性閉角型青光眼預測及治療方案制定中的應用研究報告

目錄 一、引言 1.1 研究背景與意義 1.2 研究目的與方法 1.3 國內外研究現狀 二、原發性急性閉角型青光眼概述 2.1 疾病定義與分類 2.2 發病機制與危險因素 2.3 癥狀與診斷方法 三、大模型在原發性急性閉角型青光眼預測中的應用 3.1 大模型原理與優勢 3.2 術前風險預…

【藍橋杯—單片機】第十五屆省賽真題代碼題解析 | 思路整理

第十五屆省賽真題代碼題解析 前言賽題代碼思路筆記競賽板配置建立模板明確基本要求顯示功能部分頻率界面正常顯示高位熄滅 參數界面基礎寫法:兩個界面分開來寫優化寫法:兩個界面合一起寫 時間界面回顯界面校準校準過程校準錯誤顯示 DAC輸出部分按鍵功能部…

Vue3實戰學習(Vue3快速搭建后臺管理系統(網頁頭部、側邊導航欄、主體數據展示區的設計與實現)(超詳細))(9)

目錄 一、Vue3工程環境配置、項目基礎腳手架搭建、Vue3基礎語法、Vue3集成Element-Plus的詳細教程。(博客鏈接如下) 二、Vue3集成Element-Plus詳細教程。(博客鏈接如下) 三、Vue3集成Vue-Router詳細教程。(博客鏈接如下) 四、Vue3快速搭建后臺管理系統。(實戰學習) &#xff08…

halcon機器人視覺(四)calibrate_hand_eye_stationary_3d_sensor

目錄 一、準備數據和模型二、按照表面匹配的的結果進行手眼標定三、根據標定結果計算CalObjInCamPose一、準備數據和模型 1、讀3D模型:read_object_model_3d 2、創建表面匹配模板:create_surface_model 3、創建一個HALCON校準數據模型:create_calib_data read_object_mode…

【菜鳥飛】通過vsCode用python訪問deepseek-r1等模型

目標 通過vsCode用python訪問deepseek。 環境準備 沒有環境的,vscode環境準備請參考之前的文章,另外需安裝ollama: 【菜鳥飛】用vsCode搭建python運行環境-CSDN博客 AI入門1:AI模型管家婆ollama的安裝和使用-CSDN博客 選讀文章…

vue中,watch里,this為undefined的兩種解決辦法

提示:vue中,watch里,this為undefined的兩種解決辦法 文章目錄 [TOC](文章目錄) 前言一、問題二、方法1——使用function函數代替箭頭函數()>{}三、方法2——使用that總結 前言 ?????盡量使用方法1——使用function函數代替箭頭函數()…

【如何使用云服務器與API搭建專屬聊天系統:寶塔面板 + Openwebui 完整教程】

文章目錄 不挑電腦、不用技術,云服務器 API 輕松搭建專屬聊天系統,對接 200 模型,數據全在自己服務器,安全超高一、前置準備:3 分鐘快速上手指南云服務器準備相關賬號注冊 二、手把手部署教程(含代碼塊&a…

使用 PresentMon 獲取屏幕幀率

PresentMon是一個用于捕獲和分析Windows上圖形應用程序高性能特性的工具集,最初由GameTechDev開發,現由英特爾維護和推廣。PresentMon能夠追蹤關鍵性能指標,如CPU、GPU和顯示器的幀持續時間和延遲等,并支持多種圖形API(如DirectX、OpenGL和Vulkan)以及不同的硬件配置和桌…

基金交易系統的流程

1. 賬戶管理 開戶:投資者在基金銷售機構(如銀行、券商或第三方平臺)開立基金賬戶和資金賬戶。賬戶驗證:驗證投資者身份,綁定銀行卡或其他支付方式。 2. 交易申請 投資者下單:通過交易終端(APP…

vue2雙向綁定解析

Vue 2 的雙向綁定原理基于 Object.defineProperty,核心源碼在 src/core/observer 目錄中。 1. 核心模塊:observer observer 模塊負責將普通對象轉換為響應式對象,主要包括以下文件: index.js:定義 Observer 類&#…

中級軟件設計師2004-2024軟考真題合集下載

中級軟件設計師2004-2024軟考真題合集下載 🌟 資源亮點🎯 適用人群💡 資源使用指南📌 資源獲取方式 🌟 資源亮點 「中級軟件設計師歷年真題及答案解析(2004-2024)」 是全網最全、最新的備考資料…

艾爾登復刻Ep1——客戶端制作、場景切換、網絡控制

需要添加的插件內容 Netcode for GameObjects:是一個為 Unity 游戲開發提供高級網絡功能的 SDK。它的主要作用是允許開發者在其 GameObject 和 MonoBehaviour 工作流中集成網絡功能,并且可以與多種底層傳輸層協議兼容。 具體內容請看:https:…

2025探索短劇行業新可能報告40+份匯總解讀|附PDF下載

原文鏈接:https://tecdat.cn/?p41043 近年來,短劇以其緊湊的劇情、碎片化的觀看體驗,迅速吸引了大量用戶。百度作為互聯網巨頭,在短劇領域積極布局。從早期建立行業專屬模型冷啟動,到如今構建完整的商業生態&#xf…

正常的一個編碼器的架構是怎么樣,有哪些模塊構成

正常的一個編碼器架構及其模塊構成 在音視頻編碼器(Video Encoder)中,通常包括多個核心模塊,整個編碼器架構遵循 輸入 -> 預處理 -> 編碼核心 -> 碼流封裝 的流程。 1. 編碼器的整體架構 編碼器的主要架構如下&#xf…

文件解析漏洞練習

iis6的目錄解析漏洞 (.asp目錄中的所有文件都會被當做asp文件執行) 1.在iis的網站根目錄新建一個名為x.asp的文件 2.在x.asp中新建一個jpg文件。內容為<%now()%> asp代碼。 3.在外部瀏覽器中訪問windows2003的iis網站中的2.jpg 發現asp代碼被執行 iis6的分號截斷解析漏洞…

SQL Server性能優化實戰:從瓶頸定位到高效調優

引言 在數據庫應用中,性能問題直接影響用戶體驗和系統穩定性。本文基于實際案例,分享SQL Server性能優化的關鍵步驟與實用技巧,涵蓋問題定位、索引優化、查詢調優等多個維度。 目錄 引言 一、性能瓶頸定位 1.1 監控工具使用 二、索引優化實戰 2.1 索引碎片整理 2.2 缺…

【DNS系列】使用TCP傳輸

DNS ?默認使用UDP協議?&#xff08;端口53&#xff09;進行通信&#xff0c;但在以下場景中會切換到TCP協議?&#xff08;端口53&#xff09;&#xff1a; ?1. 響應數據過大&#xff08;超過512字節&#xff09;? ?UDP限制&#xff1a;DNS的UDP協議默認限制單個數據包大…

Go Ebiten小游戲開發:俄羅斯方塊

在這篇文章中&#xff0c;我們將一起開發一個簡單的俄羅斯方塊游戲&#xff0c;使用Go語言和Ebiten游戲庫。Ebiten是一個輕量級的游戲庫&#xff0c;適合快速開發2D游戲。我們將逐步構建游戲的基本功能&#xff0c;包括游戲邏輯、圖形繪制和用戶輸入處理。 項目結構 我們的項…

MySQL中IN關鍵字與EXIST關鍵字的比較

文章目錄 **功能等價性分析****執行計劃分析**&#xff1a; **1. EXISTS 的工作原理****步驟拆解**&#xff1a; **2. 為什么需要“利用索引快速定位”&#xff1f;****索引作用示例**&#xff1a; **3. 與 IN 子查詢的對比****IN 的工作方式**&#xff1a;**關鍵差異**&#x…

## DeepSeek寫水果記憶配對手機小游戲

DeepSeek寫水果記憶配對手機小游戲 提問 根據提的要求&#xff0c;讓DeepSeek整理的需求&#xff0c;進行提問&#xff0c;內容如下&#xff1a; 請生成一個包含以下功能的可運行移動端水果記憶配對小游戲H5文件&#xff1a; 要求 可以重新開始游戲 可以暫停游戲 卡片里的水果…