最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的synchronized關(guān)鍵字全解析

 更新時(shí)間:2026年01月15日 08:46:17   作者:我會(huì)替風(fēng)去  
synchronized是Java中用于解決并發(fā)問題的核心關(guān)鍵字,通過確保多個(gè)線程對共享資源的互斥訪問,來避免線程安全問題,synchronized具有原子性、可見性、有序性和可重入性等特性,本文給大家介紹Java中的synchronized關(guān)鍵字相關(guān),感興趣的朋友跟隨小編一起看看吧

synchronized是Java中用于解決并發(fā)問題的核心關(guān)鍵字,它通過確保多個(gè)線程對共享資源的互斥訪問,來避免線程安全問題(如競態(tài)條件、數(shù)據(jù)不一致等)。

synchronized的核心特性

  • 原子性(Atomicity):確保一個(gè)或多個(gè)操作要么全部執(zhí)行成功,要么全部執(zhí)行失敗。在synchronized代碼塊中的代碼是不可中斷的,同一時(shí)刻只有一個(gè)線程能執(zhí)行。
  • 可見性(Visibility):保證一個(gè)線程對共享變量的修改,對于其他后續(xù)進(jìn)入同步代碼塊的線程是可見的。當(dāng)線程釋放鎖時(shí),會(huì)將私有內(nèi)存中的變量值刷新回主內(nèi)存。
  • 有序性(Ordering):雖然編譯器和處理器為了優(yōu)化會(huì)進(jìn)行指令重排,但synchronized可以保證多線程程序在邏輯上的執(zhí)行順序,即“同步塊內(nèi)的代碼在執(zhí)行上具有先后順序”。
  • 可重入性:可重入性是指一個(gè)線程已經(jīng)獲取到某個(gè)鎖后,再次請求該鎖時(shí)可以直接獲取,無需重新競爭。synchronized是可重入鎖,其內(nèi)部通過計(jì)數(shù)器記錄鎖的持有次數(shù)(初始為0,獲取鎖時(shí)加1,釋放鎖時(shí)減1,計(jì)數(shù)器為0時(shí)鎖才被真正釋放)。這一特性避免了線程在遞歸調(diào)用同步方法/代碼塊時(shí)出現(xiàn)死鎖。例如,一個(gè)同步方法A調(diào)用另一個(gè)同步方法B(兩者鎖對象相同),線程獲取A的鎖后,調(diào)用B時(shí)可直接獲取鎖。

synchronized的使用方式

synchronized的使用靈活,可修飾不同的代碼結(jié)構(gòu),核心是明確“鎖對象”——線程競爭的是鎖對象,只有獲取到鎖對象的線程才能執(zhí)行同步代碼,常見使用方式有3種。

  • 修飾實(shí)例方法(對象鎖),語法:public synchronized void methodName() { ... }
  • 鎖對象:當(dāng)前類的實(shí)例對象(this)。
  • 特點(diǎn):不同實(shí)例對象的鎖相互獨(dú)立,即多個(gè)線程訪問同一個(gè)實(shí)例的同步實(shí)例方法時(shí)會(huì)競爭鎖;訪問不同實(shí)例的同步實(shí)例方法時(shí),因鎖對象不同,不會(huì)競爭。
  • 示例:同一User實(shí)例的add()方法被多線程調(diào)用時(shí)互斥,不同User實(shí)例的add()方法可并行執(zhí)行。
  • 修飾靜態(tài)方法(類鎖)語法:public static synchronized void methodName() { ... }
  • 鎖對象:當(dāng)前類的Class對象(每個(gè)類在JVM中只有一個(gè)Class對象,是全局唯一的)。
  • 特點(diǎn):類鎖是全局鎖,無論創(chuàng)建多少個(gè)類的實(shí)例,所有線程訪問該類的同步靜態(tài)方法時(shí),都會(huì)競爭同一個(gè)Class對象鎖。
  • 注意:類鎖與對象鎖相互獨(dú)立,即同步靜態(tài)方法和同步實(shí)例方法的鎖對象不同,線程訪問時(shí)不會(huì)競爭。
  • 修飾代碼塊(自定義鎖對象),語法:synchronized (鎖對象) { ... 同步代碼 ... }
  • 鎖對象:可自定義,支持兩種類型:① 實(shí)例對象(this或其他實(shí)例);② Class對象(類名.class)。
  • 特點(diǎn):粒度最細(xì),可精準(zhǔn)控制需要同步的代碼片段(而非整個(gè)方法),減少鎖競爭,提高程序性能。
  • 常見場景:
    • 鎖當(dāng)前實(shí)例:synchronized (this) { ... },效果與修飾實(shí)例方法一致,但僅同步代碼塊內(nèi)的邏輯。
    • 鎖Class對象:synchronized (User.class) { ... },效果與修飾靜態(tài)方法一致。
    • 鎖自定義對象:private Object lock = new Object(); synchronized (lock) { ... },通過獨(dú)立的鎖對象,避免與其他同步邏輯競爭鎖,靈活性最高。

synchronized的鎖機(jī)制

  • Java 6及以后對synchronized進(jìn)行了大幅優(yōu)化,引入了“偏向鎖、輕量級鎖、重量級鎖”三種鎖狀態(tài),目的是根據(jù)線程競爭的激烈程度動(dòng)態(tài)切換鎖狀態(tài),平衡性能與線程安全。鎖機(jī)制的核心是“對象頭”——Java對象在內(nèi)存中的布局包括對象頭、實(shí)例數(shù)據(jù)、對齊填充,其中對象頭存儲(chǔ)了鎖的狀態(tài)信息(Mark Word)、類元數(shù)據(jù)指針等。
  • 三種鎖狀態(tài)的優(yōu)先級:無鎖 < 偏向鎖 < 輕量級鎖 < 重量級鎖,隨著線程競爭的加劇,鎖會(huì)從低級別向高級別升級,且升級過程不可逆(一旦升級為重量級鎖,無法回退為輕量級鎖或偏向鎖)。
    • 無鎖(No Lock):初始狀態(tài)。
    • 偏向鎖(Biased Lock):當(dāng)只有一個(gè)線程訪問同步塊時(shí),直接在對象頭記錄線程ID,下次該線程進(jìn)入時(shí)無需CAS操作,性能極高。
    • 輕量級鎖(Lightweight Lock):當(dāng)出現(xiàn)競爭,但競爭不激烈時(shí),通過CAS自旋來嘗試獲取鎖,避免線程阻塞。
    • 重量級鎖(Heavyweight Lock):當(dāng)自旋超過一定次數(shù)或競爭非常激烈時(shí),升級為重量級鎖。此時(shí)未獲取到鎖的線程會(huì)進(jìn)入阻塞(Blocked)狀態(tài),交給操作系統(tǒng)管理。

鎖優(yōu)化補(bǔ)充

  • 鎖消除:JVM的即時(shí)編譯器(JIT)在運(yùn)行時(shí),會(huì)對一些“不可能存在競爭的鎖”進(jìn)行消除。例如,局部變量作為鎖對象(每個(gè)線程都有獨(dú)立的局部變量,無共享),JVM會(huì)直接刪除該synchronized修飾,避免不必要的鎖開銷。
  • 鎖粗化:當(dāng)多個(gè)連續(xù)的synchronized代碼塊使用同一個(gè)鎖對象時(shí),JVM會(huì)將這些代碼塊合并為一個(gè)大的同步代碼塊,減少鎖的獲取/釋放次數(shù)(每次獲取/釋放鎖都有開銷)。例如,循環(huán)內(nèi)多次調(diào)用同步方法,JVM可能將鎖粗化到循環(huán)外部。

CAS (Compare And Swap,比較并交換) 是并發(fā)編程中實(shí)現(xiàn)原子操作的核心算法,是一種樂觀鎖的實(shí)現(xiàn)策略。

  • CAS的工作原理,包含三個(gè)核心參數(shù):
  • 內(nèi)存地址 V (Memory Location):變量在內(nèi)存中的實(shí)際值。
  • 期望值 A (Expected Value):線程認(rèn)為該變量當(dāng)前應(yīng)該是什么值。
  • 新值 B (New Value):線程想要更新成的值。
  • 執(zhí)行邏輯:當(dāng)且僅當(dāng)內(nèi)存地址 V 的值等于期望值 A 時(shí),處理器才會(huì)將 V 的值更新為 B。否則,說明該變量已被其他線程修改,當(dāng)前線程什么都不做,通常會(huì)進(jìn)入自旋(死循環(huán)重試)。
  • CAS的優(yōu)缺點(diǎn)
    優(yōu)點(diǎn):
  • 非阻塞性:CAS 是一種非阻塞算法(Non-blocking),它不需要像 synchronized 那樣掛起和恢復(fù)線程。
  • 性能高:在低、中度競爭的情況下,由于減少了線程上下文切換的開銷,效率遠(yuǎn)高于重量級鎖。
    缺點(diǎn):
  • 循環(huán)時(shí)間長(自旋開銷):如果高并發(fā)下競爭激烈,CAS 會(huì)頻繁失敗并不斷自旋,這會(huì)給 CPU 帶來巨大的計(jì)算壓力。
  • 只能保證一個(gè)共享變量的原子操作:對于多個(gè)變量的操作,仍需使用 synchronized 或 ReentrantLock。
  • ABA 問題(最經(jīng)典的缺點(diǎn))。
  • 什么是 ABA 問題?
  • 如果變量初始值為A,在線程1準(zhǔn)備修改它的過程中,線程2快速地將其改成了B,然后又改回了A。 現(xiàn)象:線程1觀察到值依然是A,認(rèn)為它沒變過,于是CAS成功。 風(fēng)險(xiǎn):雖然數(shù)值沒變,但變量的狀態(tài)(或?qū)ο髢?nèi)部的屬性)可能已經(jīng)發(fā)生了變化,導(dǎo)致邏輯錯(cuò)誤。
  • Java提供了AtomicStampedReference類,通過引入版本號(Stamp)來解決: 每次變量更新時(shí),不僅更新值,還增加一個(gè)版本號。只有值和版本號都一致,CAS才會(huì)成功。
  • 還可以設(shè)置時(shí)間戳來解決。
  • CAS 在Java中的實(shí)現(xiàn)
  • 在Java中,CAS主要由 sun.misc.Unsafe 類提供支持。該類中的方法(如 compareAndSwapInt)是 native 的,直接調(diào)用硬件底層的指令。

ReentrantLock(可重入鎖)

  • ReentrantLock是 Java java.util.concurrent.locks 包下的可重入鎖實(shí)現(xiàn),基于 AQS(抽象隊(duì)列同步器)構(gòu)建,是 synchronized 的 “增強(qiáng)版”—— 既保留了 synchronized 的可重入特性,又提供了更靈活的同步控制能力。

兩者對比:

特性synchronizedReentrantLock
實(shí)現(xiàn)層面JVM 層面(關(guān)鍵字),由 C++ 實(shí)現(xiàn)JDK 層面(API),由 Java 編寫(基于 AQS)
鎖的釋放自動(dòng)釋放(代碼執(zhí)行完或異常后)手動(dòng)釋放(必須在 finally 中調(diào)用 unlock())
靈活性低(不可中斷,無超時(shí)機(jī)制)高(支持嘗試獲取、超時(shí)獲取、可中斷獲?。?/td>
公平性只支持非公平鎖支持公平鎖與非公平鎖(默認(rèn)非公平)
等待隊(duì)列只能關(guān)聯(lián) 1 個(gè) 等待隊(duì)列(wait/notify)可以綁定 多個(gè) Condition(精細(xì)化喚醒)

ReentrantLock的特有高級功能

  • 響應(yīng)中斷 (lockInterruptibly)
  • synchronized一旦進(jìn)入阻塞等待,除非拿到鎖,否則無法被中斷。而ReentrantLock允許線程在等待鎖的過程中響應(yīng)Thread.interrupt(),從而避免死等。
  • 超時(shí)機(jī)制 (tryLock)
  • 線程可以嘗試獲取鎖,如果鎖被占用,立即返回 false 或者等待一段時(shí)間后返回,而不是一直阻塞。這在預(yù)防死鎖時(shí)非常有用。
  • 公平鎖 (Fairness)
  • 公平鎖:按照線程請求鎖的順序分配,先到先得。
  • 非公平鎖(默認(rèn)):允許“插隊(duì)”。如果新來的線程正好碰到鎖釋放,它可以直接搶占,性能通常比公平鎖高。
  • 多個(gè) Condition 對象
  • 通過lock.newCondition(),你可以創(chuàng)建多個(gè)等待集。例如在阻塞隊(duì)列中,可以定義 notFull 和 notEmpty 兩個(gè)條件,實(shí)現(xiàn)比 notifyAll 更精準(zhǔn)的線程喚醒。

基本使用示例:

import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo {
    // 創(chuàng)建非公平鎖(默認(rèn)),若需公平鎖:new ReentrantLock(true)
    private static final ReentrantLock lock = new ReentrantLock();
    public static void doTask() {
        // 1. 普通獲取鎖(不可中斷)
        lock.lock();
        try {
            // 臨界區(qū)代碼(線程安全)
            System.out.println(Thread.currentThread().getName() + " 執(zhí)行任務(wù)");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 必須在finally中釋放鎖,否則鎖永遠(yuǎn)無法釋放
            lock.unlock();
        }
    }
    // 超時(shí)獲取鎖示例
    public static void tryLockWithTimeout() {
        try {
            // 嘗試在2秒內(nèi)獲取鎖,獲取成功返回true,失敗返回false
            if (lock.tryLock(2, java.util.concurrent.TimeUnit.SECONDS)) {
                try {
                    System.out.println(Thread.currentThread().getName() + " 超時(shí)獲取鎖成功");
                } finally {
                    lock.unlock();
                }
            } else {
                System.out.println(Thread.currentThread().getName() + " 超時(shí)獲取鎖失敗");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    public static void main(String[] args) {
        // 測試普通獲取鎖
        new Thread(ReentrantLockDemo::doTask, "線程1").start();
        new Thread(ReentrantLockDemo::doTask, "線程2").start();
        // 測試超時(shí)獲取鎖
        new Thread(ReentrantLockDemo::tryLockWithTimeout, "線程3").start();
    }
}

到此這篇關(guān)于Java中的synchronized關(guān)鍵字全解析的文章就介紹到這了,更多相關(guān)java synchronized關(guān)鍵字內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JVM虛擬機(jī)的執(zhí)行流程解析

    JVM虛擬機(jī)的執(zhí)行流程解析

    這篇文章主要介紹了JVM虛擬機(jī)的執(zhí)行流程圖解,Java虛擬機(jī)的啟動(dòng)是通過引導(dǎo)類加載器創(chuàng)建一個(gè)初始類來完成的,這個(gè)類是由虛擬機(jī)的具體實(shí)現(xiàn)指定的,程序開始執(zhí)行時(shí)他才運(yùn)行,程序結(jié)束時(shí)他就停止,需要的朋友可以參考下
    2023-08-08
  • springboot2 生產(chǎn)部署注意事項(xiàng)及示例代碼

    springboot2 生產(chǎn)部署注意事項(xiàng)及示例代碼

    這篇文章主要介紹了springboot2 生產(chǎn)部署注意事項(xiàng)及示例代碼,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-04-04
  • java8如何用Stream查List對象某屬性是否有重復(fù)

    java8如何用Stream查List對象某屬性是否有重復(fù)

    這篇文章主要介紹了java8如何用Stream查List對象某屬性是否有重復(fù)的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SLF4J報(bào)錯(cuò)解決:No SLF4J providers were found的問題

    SLF4J報(bào)錯(cuò)解決:No SLF4J providers were found的

    這篇文章主要介紹了SLF4J報(bào)錯(cuò)解決:No SLF4J providers were found的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Java求兩集合的交集、并集、差集實(shí)例

    Java求兩集合的交集、并集、差集實(shí)例

    這篇文章主要介紹了Java求兩集合的交集、并集、差集實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 學(xué)習(xí)Java之異常到底該如何捕獲和處理

    學(xué)習(xí)Java之異常到底該如何捕獲和處理

    我們知道,Java的異常處理是通過5個(gè)關(guān)鍵字來實(shí)現(xiàn)的,即try、catch、throw、throws和finally,try?catch語句用于捕獲并處理異常,但具體該怎么捕獲異常,怎么拋出異常,什么時(shí)候拋,什么時(shí)候捕,感興趣的小伙伴跟著小編一起來看看吧
    2023-08-08
  • Java漢字轉(zhuǎn)拼音案例詳解

    Java漢字轉(zhuǎn)拼音案例詳解

    這篇文章主要介紹了Java漢字轉(zhuǎn)拼音案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • SpringCloud GateWay動(dòng)態(tài)路由用法

    SpringCloud GateWay動(dòng)態(tài)路由用法

    網(wǎng)關(guān)作為所有項(xiàng)目的入口,不希望重啟,因此動(dòng)態(tài)路由是必須的,動(dòng)態(tài)路由主要通過RouteDefinitionRepository接口實(shí)現(xiàn),其默認(rèn)的實(shí)現(xiàn)是InMemoryRouteDefinitionRepository,即在內(nèi)存中存儲(chǔ)路由配置,可基于這個(gè)map對象操作,動(dòng)態(tài)路由的實(shí)現(xiàn)方案有兩種
    2024-10-10
  • 解決idea中maven項(xiàng)目打包成jar報(bào)錯(cuò):沒有主清單屬性的問題

    解決idea中maven項(xiàng)目打包成jar報(bào)錯(cuò):沒有主清單屬性的問題

    這篇文章主要給大家分享了idea中maven項(xiàng)目打包成jar,報(bào)錯(cuò)沒有主清單屬性解決方法,文中有詳細(xì)的解決方法,如果又遇到同樣問題的朋友可以參考一下本文
    2023-09-09
  • Spring注解驅(qū)動(dòng)之BeanPostProcessor后置處理器講解

    Spring注解驅(qū)動(dòng)之BeanPostProcessor后置處理器講解

    這篇文章主要介紹了Spring注解驅(qū)動(dòng)之BeanPostProcessor后置處理器講解,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09

最新評論

云安县| 中江县| 耒阳市| 察雅县| 三门县| 天台县| 辉县市| 合肥市| 呼伦贝尔市| 从江县| 常山县| 沭阳县| 建湖县| 沧州市| 临夏县| 赤水市| 新丰县| 清丰县| 温宿县| 上犹县| 乐安县| 金山区| 伊宁市| 桂林市| 铜山县| 富宁县| 萝北县| 通山县| 自贡市| 陈巴尔虎旗| 吐鲁番市| 巴林左旗| 若尔盖县| 葫芦岛市| 墨脱县| 特克斯县| 黄石市| 都匀市| 洛南县| 临江市| 崇义县|