Java 中 synchronized 的使用方式和鎖升級
在 Java 并發(fā)編程中,synchronized
是一個非常重要的關(guān)鍵字,用于實現(xiàn)線程同步,保證在同一時刻只有一個線程可以訪問被同步的代碼塊或方法,從而避免多線程帶來的數(shù)據(jù)不一致等問題。同時,Java 虛擬機(JVM)為了提高ynchronized
的性能,引入了鎖升級機制。下面我們就來詳細(xì)介紹ynchronized
的使用和鎖升級過程。
一、synchronized 的使用方式
(一)修飾普通方法
當(dāng)synchronized
修飾一個普通方法時,鎖對象是當(dāng)前對象(this
)。也就是說,當(dāng)一個線程進(jìn)入該方法時,會自動獲取當(dāng)前對象的鎖,其他線程想要進(jìn)入該方法,必須等待當(dāng)前線程釋放鎖。例如:
public class SynchronizedExample { public synchronized void synchronizedMethod() { // 線程同步的代碼邏輯 System.out.println("線程 " + Thread.currentThread().getName() + " 進(jìn)入同步方法"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程 " + Thread.currentThread().getName() + " 退出同步方法"); } }
在上述代碼中,synchronizedMethod
是一個同步方法,多個線程同時調(diào)用該方法時,會依次排隊執(zhí)行,保證了方法內(nèi)代碼的線程安全性。
(二)修飾靜態(tài)方法
當(dāng)synchronized
修飾靜態(tài)方法時,鎖對象是該類的Class
對象。因為靜態(tài)方法屬于類級別,不依賴于具體的對象實例,所以使用類的Class
對象作為鎖。示例如下:
public class StaticSynchronizedExample { public static synchronized void staticSynchronizedMethod() { System.out.println("線程 " + Thread.currentThread().getName() + " 進(jìn)入靜態(tài)同步方法"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程 " + Thread.currentThread().getName() + " 退出靜態(tài)同步方法"); } }
多個線程調(diào)用staticSynchronizedMethod
時,會對類的Class
對象進(jìn)行加鎖,從而實現(xiàn)線程同步。
(三)修飾代碼塊
synchronized
還可以修飾代碼塊,此時需要顯式指定鎖對象。鎖對象可以是任意對象,只要保證在需要同步的代碼塊中使用相同的鎖對象即可。比如:
public class BlockSynchronizedExample { private Object lock = new Object(); public void blockSynchronized() { synchronized (lock) { System.out.println("線程 " + Thread.currentThread().getName() + " 進(jìn)入同步代碼塊"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程 " + Thread.currentThread().getName() + " 退出同步代碼塊"); } } }
在這個例子中,lock
對象作為同步代碼塊的鎖,多個線程訪問blockSynchronized
方法時,會競爭lock
對象的鎖。
二、synchronized 的鎖升級
為了提高synchronized
的性能,JVM 引入了鎖升級機制,從無鎖狀態(tài)開始,根據(jù)競爭情況逐步升級為偏向鎖、輕量級鎖和重量級鎖。
(一)無鎖
無鎖狀態(tài)是最基本的狀態(tài),當(dāng)沒有線程競爭鎖時,對象處于無鎖狀態(tài)。此時,線程可以直接訪問被synchronized
修飾的代碼,無需進(jìn)行任何加鎖操作,因此性能最高。
(二)偏向鎖
當(dāng)一個線程首次訪問被synchronized
修飾的代碼時,JVM 會將對象頭中的鎖標(biāo)志位設(shè)置為偏向鎖模式,并將該線程的 ID 記錄在對象頭中。此后,當(dāng)該線程再次訪問同一對象的同步代碼時,無需進(jìn)行額外的加鎖操作,直接進(jìn)入同步代碼塊,因為 JVM 認(rèn)為該線程很可能會再次訪問。偏向鎖的存在減少了無競爭情況下的鎖開銷。
(三)輕量級鎖
當(dāng)有第二個線程試圖訪問同一個對象的同步代碼時,偏向鎖會升級為輕量級鎖。JVM 會在當(dāng)前線程的棧幀中創(chuàng)建一個鎖記錄(Lock Record),并將對象頭中的 Mark Word 復(fù)制到鎖記錄中,然后嘗試使用 CAS(Compare - And - Swap,比較并交換)操作將對象頭的 Mark Word 替換為指向鎖記錄的指針。如果 CAS 操作成功,當(dāng)前線程就獲得了輕量級鎖,可以進(jìn)入同步代碼塊;如果失敗,說明存在競爭,輕量級鎖會升級為重量級鎖。
(四)重量級鎖
當(dāng)輕量級鎖競爭失敗,即多個線程同時競爭鎖時,會升級為重量級鎖。此時,JVM 會使用操作系統(tǒng)的互斥量(Mutex)來實現(xiàn)鎖機制,線程會進(jìn)入阻塞狀態(tài),等待鎖的釋放。重量級鎖的性能相對較低,因為線程的阻塞和喚醒需要操作系統(tǒng)的干預(yù),會帶來較大的開銷。
鎖升級的過程是 JVM 根據(jù)實際的線程競爭情況動態(tài)調(diào)整的,目的是在保證線程安全性的同時,盡可能提高synchronized
的性能。
總之,synchronized
是 Java 并發(fā)編程中實現(xiàn)線程同步的重要手段,理解其使用方式和鎖升級機制,對于編寫高效、安全的多線程程序具有重要意義。在實際開發(fā)中,我們應(yīng)該根據(jù)具體的場景合理使用synchronized
,并注意鎖的粒度和性能優(yōu)化,以充分發(fā)揮多線程的優(yōu)勢。
到此這篇關(guān)于Java 中 synchronized 的使用和鎖升級的文章就介紹到這了,更多相關(guān)Java synchronized 使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java中的synchronized有幾種加鎖方式(實例詳解)
- Java中復(fù)雜的Synchronized關(guān)鍵字使用方法詳解
- Java中synchronized的四種用法詳解
- Java關(guān)鍵字synchronized基本使用詳解
- Java并發(fā)編程中的synchronized關(guān)鍵字詳細(xì)解讀
- Java?synchronized關(guān)鍵字性能考量及優(yōu)化探索
- 深入了解Java中Synchronized關(guān)鍵字的實現(xiàn)原理
- 一文帶你搞懂Java中Synchronized和Lock的原理與使用
- Java同步鎖synchronized用法的最全總結(jié)
相關(guān)文章
springboot登陸頁面圖片驗證碼簡單的web項目實現(xiàn)
這篇文章主要介紹了springboot登陸頁面圖片驗證碼簡單的web項目實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04Springboot與vue實例講解實現(xiàn)前后端分離的人事管理系統(tǒng)
這篇文章主要介紹了如何用Java實現(xiàn)企業(yè)人事管理系統(tǒng),文中采用springboot+vue實現(xiàn)前后端分離,感興趣的小伙伴可以學(xué)習(xí)一下2022-06-06java CompletableFuture實現(xiàn)異步編排詳解
這篇文章主要為大家介紹了java CompletableFuture實現(xiàn)異步編排詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01SpringBoot實現(xiàn)發(fā)送郵件功能過程圖解
這篇文章主要介紹了SpringBoot實現(xiàn)發(fā)送郵件功能過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03往DAO類中注入@PersistenceContext和@Resource的區(qū)別詳解
這篇文章主要介紹了往DAO類中注入@PersistenceContext和@Resource的區(qū)別詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02