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

Java?CAS與JUC組件詳解

 更新時(shí)間:2025年04月23日 09:59:46   作者:愛(ài)吃烤雞翅的酸菜魚(yú)  
CAS是一種基于樂(lè)觀鎖的無(wú)鎖并發(fā)控制技術(shù),其核心邏輯可以概括為:“我認(rèn)為當(dāng)前值應(yīng)該是A,如果是,則更新為B;否則放棄或重試”,整個(gè)過(guò)程由硬件保證原子性,無(wú)需傳統(tǒng)鎖機(jī)制,本文給大家介紹Java?CAS與JUC組件的相關(guān)知識(shí),感興趣的朋友一起看看吧

1.前言

哈嘍大家好吖,不知不覺(jué)多線程這一塊大骨頭終于快要啃完了,今天給大家分享的是CAS以及JUC相關(guān)組件,那么廢話不多說(shuō)讓我們開(kāi)始吧。

2.正文

2.1CAS概念

核心思想:無(wú)所并發(fā)控制

CAS(Compare And Swap)是一種基于樂(lè)觀鎖的無(wú)鎖并發(fā)控制技術(shù)。其核心邏輯可以概括為:“我認(rèn)為當(dāng)前值應(yīng)該是A,如果是,則更新為B;否則放棄或重試”。整個(gè)過(guò)程由硬件保證原子性,無(wú)需傳統(tǒng)鎖機(jī)制。

通俗來(lái)說(shuō)
假設(shè)你和同事協(xié)同編輯一份共享文檔,每次保存時(shí)系統(tǒng)會(huì)檢查:

當(dāng)前內(nèi)容是否和你打開(kāi)時(shí)的版本一致(預(yù)期值比對(duì))。

如果一致,允許保存;否則提示“內(nèi)容已變更,請(qǐng)重新編輯”。
這個(gè)過(guò)程就是CAS的核心思想——樂(lè)觀鎖:先操作,沖突時(shí)重試,而非直接加鎖阻塞。

CAS操作的偽代碼可以拆解為以下步驟,幫助理解其原子性本質(zhì):

// 偽代碼:CAS操作的邏輯分解
public boolean compareAndSwap(MemoryAddress addr, int expectedValue, int newValue) {
    // 1. 讀取內(nèi)存當(dāng)前值
    int currentValue = *addr; 
    // 2. 比較當(dāng)前值與預(yù)期值
    if (currentValue != expectedValue) {
        return false; // 值已被其他線程修改,操作失敗
    }
    // 3. 若值未變,執(zhí)行原子性更新
    *addr = newValue;
    return true;
}

2.2CAS兩種用途

2.2.1實(shí)現(xiàn)原子類(lèi)

針對(duì)原子類(lèi),++--這樣的操作是原子的,基于CAS實(shí)現(xiàn),不涉及到加鎖。

傳統(tǒng)實(shí)現(xiàn):

private int count = 0;  
public synchronized void increment() {  
    count++;  
}  

進(jìn)階實(shí)現(xiàn): (使用Java提供的原子類(lèi))

AtomicInteger count = new AtomicInteger(0);  
public void increment() {  
    int oldValue, newValue;  
    do {  
        oldValue = count.get();  
        newValue = oldValue + 1;  
    } while (!count.compareAndSet(oldValue, newValue)); // CAS自旋  
}  

2.2.2實(shí)現(xiàn)自旋鎖

先回顧一個(gè)上篇文章的概念:自旋鎖是線程通過(guò)循環(huán)(自旋)不斷嘗試獲取鎖,而非立即阻塞。適用于鎖持有時(shí)間極短的場(chǎng)景。

代碼實(shí)現(xiàn):

public class CASSpinLock {  
    private AtomicBoolean locked = new AtomicBoolean(false);  
    // 獲取鎖  
    public void lock() {  
        while (!locked.compareAndSet(false, true)) {  
            // 自旋:直到成功將locked從false改為true  
        }  
    }  
    // 釋放鎖  
    public void unlock() {  
        locked.set(false);  
    }  
}  

線程競(jìng)爭(zhēng)不激烈時(shí)(如短任務(wù)),自旋鎖比系統(tǒng)鎖(如synchronized)更高效。

缺點(diǎn):長(zhǎng)時(shí)間自旋會(huì)浪費(fèi)CPU資源(需根據(jù)場(chǎng)景權(quán)衡)。

2.3缺陷:ABA問(wèn)題

ABA問(wèn)題場(chǎng)景

  • 線程1讀取變量值為A。
  • 線程2將值改為B,隨后又改回A。
  • 線程1執(zhí)行CAS操作,發(fā)現(xiàn)當(dāng)前值仍是A,誤認(rèn)為未被修改過(guò),操作成功。

通俗理解:

  • 你看到自己的水杯是滿(mǎn)的(A),去接水時(shí)離開(kāi)了一會(huì)兒。
  • 期間別人喝光水(A→B)又倒?jié)M(B→A)。
  • 你回來(lái)后以為水沒(méi)被喝過(guò),直接喝下(可能喝到別人的水?。?/li>

這里在實(shí)際場(chǎng)景中就是非常嚴(yán)重的線程安全的問(wèn)題了。

解決方案: 

1. 版本號(hào)標(biāo)記(AtomicStampedReference)
為值附加一個(gè)版本號(hào)(類(lèi)似“修改次數(shù)”),CAS時(shí)同時(shí)校驗(yàn)值和版本號(hào)。

AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);  
// 線程1讀取值和版本號(hào)  
int stamp = ref.getStamp();  
String oldValue = ref.getReference();  
// 線程2修改值并更新版本號(hào)  
ref.compareAndSet("A", "B", stamp, stamp + 1);  
ref.compareAndSet("B", "A", stamp + 1, stamp + 2);  
// 線程1嘗試修改:雖然值還是A,但版本號(hào)已變,操作失?。? 
boolean success = ref.compareAndSet(oldValue, "C", stamp, stamp + 1);  

2. 狀態(tài)標(biāo)記(AtomicMarkableReference)
用布爾值標(biāo)記是否被修改過(guò)(簡(jiǎn)化版版本號(hào))。

2.4JUC組件

2.4.1Callable接口

官方解析:Callable (Java SE 17 & JDK 17)

Callable 是 Java 并發(fā)包(JUC)中定義的接口,類(lèi)似于 Runnable,但允許線程執(zhí)行任務(wù)后返回結(jié)果,并可以拋出異常。

與 Runnable 的區(qū)別:

  • Runnable 的 run() 沒(méi)有返回值,Callable 的 call() 可以返回泛型結(jié)果。
  • call() 可以拋出受檢異常,run() 不能。

具體案例(異步運(yùn)算1加到100):

Callable<Integer> task = () -> {
    int sum = 0;
    for (int i = 1; i <= 100; i++) sum += i;
    return sum;
};
FutureTask<Integer> futureTask = new FutureTask<>(task);
new Thread(futureTask).start();
// 主線程獲取結(jié)果
System.out.println("計(jì)算結(jié)果:" + futureTask.get()); // 輸出 5050

通過(guò) FutureTask 包裝 Callable 任務(wù),啟動(dòng)線程執(zhí)行后,主線程通過(guò) futureTask.get() 等待結(jié)果返回,類(lèi)似“異步任務(wù)+回調(diào)”模式。 

2.4.2ReentrantLock(與synchronized對(duì)比)

官方解析ReentrantLock (Java SE 17 & JDK 17)

ReentrantLock 是 JUC 提供的顯式鎖,支持可重入性、可中斷鎖、公平鎖等特性。

特性synchronizedReentrantLock
鎖獲取方式隱式(JVM 管理)顯式(代碼手動(dòng)加鎖/解鎖)
可中斷不支持支持 lockInterruptibly()
公平鎖不支持支持(構(gòu)造函數(shù)指定)
條件變量(Condition)無(wú)支持(newCondition()

 案例:

class BankAccount {
    private final ReentrantLock lock = new ReentrantLock();
    private int balance = 100;
    void transfer(BankAccount target, int amount) {
        lock.lock();
        try {
            if (this.balance >= amount) {
                this.balance -= amount;
                target.balance += amount;
            }
        } finally {
            lock.unlock(); // 必須手動(dòng)釋放鎖
        }
    }
}

synchronized 的等價(jià)實(shí)現(xiàn)是在方法簽名加 synchronized 關(guān)鍵字,但 ReentrantLock 更靈活:

  • 可設(shè)置超時(shí)時(shí)間(tryLock(1, TimeUnit.SECONDS))。
  • 公平鎖減少線程饑餓問(wèn)題。

2.4.3Semaphore信號(hào)量

官方解析:Semaphore (Java SE 17 & JDK 17)

Semaphore 用于控制同時(shí)訪問(wèn)某個(gè)資源的線程數(shù)量,類(lèi)似“許可證發(fā)放”。

核心方法

  • acquire():獲取許可證(若無(wú)可用則阻塞)。
  • release():釋放許可證。

 案例:(模擬停車(chē)場(chǎng))

Semaphore semaphore = new Semaphore(3); // 3 個(gè)許可證
Runnable parkAction = () -> {
    try {
        semaphore.acquire(); // 獲取車(chē)位
        System.out.println(Thread.currentThread().getName() + " 停入車(chē)位");
        Thread.sleep(2000); // 停車(chē) 2 秒
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        semaphore.release(); // 釋放車(chē)位
        System.out.println(Thread.currentThread().getName() + " 離開(kāi)車(chē)位");
    }
};
// 啟動(dòng) 5 輛車(chē)嘗試停車(chē)
for (int i = 0; i < 5; i++) {
    new Thread(parkAction).start();
}

2.4.4CountDownLatch

官方解析:CountDownLatch (Java SE 17 & JDK 17)

CountDownLatch 是一個(gè)同步工具,允許一個(gè)或多個(gè)線程等待其他線程完成操作。

核心方法:

  • countDown():計(jì)數(shù)器減 1。
  • await():阻塞直到計(jì)數(shù)器歸零。 
public static void main(String[] args) {
        CountDownLatch latch = new CountDownLatch(3); // 需要等待 3 個(gè)任務(wù)
// 資源加載任務(wù)
        Runnable loadTask = () -> {
            try {
                Thread.sleep((long) (Math.random() * 2000));
                System.out.println(Thread.currentThread().getName() + " 加載完成");
                latch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
// 啟動(dòng) 3 個(gè)資源加載線程
        new Thread(loadTask, "地圖").start();
        new Thread(loadTask, "音效").start();
        new Thread(loadTask, "UI").start();
// 主線程等待所有資源加載完成
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("所有資源加載完成,開(kāi)始游戲!");
    }

3.小結(jié)

今天的分享到這里就結(jié)束了,喜歡的小伙伴點(diǎn)點(diǎn)贊點(diǎn)點(diǎn)關(guān)注,你的支持就是對(duì)我最大的鼓勵(lì),大家加油!

到此這篇關(guān)于Java CAS與JUC組件的文章就介紹到這了,更多相關(guān)Java CAS與JUC組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實(shí)現(xiàn)字符串與字節(jié)數(shù)組之間相互轉(zhuǎn)換

    Java實(shí)現(xiàn)字符串與字節(jié)數(shù)組之間相互轉(zhuǎn)換

    在Java編程中,字符串(String)和字節(jié)數(shù)組(byte[])之間的相互轉(zhuǎn)換是非常常見(jiàn)的操作,這種轉(zhuǎn)換在網(wǎng)絡(luò)編程、文件處理、加密解密等場(chǎng)景中尤為重要,本文將詳細(xì)介紹如何在Java中實(shí)現(xiàn)字符串與字節(jié)數(shù)組之間的相互轉(zhuǎn)換,需要的朋友可以參考下
    2025-02-02
  • Java基礎(chǔ)教程之八大基本數(shù)據(jù)類(lèi)型

    Java基礎(chǔ)教程之八大基本數(shù)據(jù)類(lèi)型

    這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)教程之八大基本數(shù)據(jù)類(lèi)型的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • 淺談java中為什么實(shí)體類(lèi)需要實(shí)現(xiàn)序列化

    淺談java中為什么實(shí)體類(lèi)需要實(shí)現(xiàn)序列化

    下面小編就為大家?guī)?lái)一篇淺談java中為什么實(shí)體類(lèi)需要實(shí)現(xiàn)序列化。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • Java異常分類(lèi)以及幾種處理機(jī)制分析講解

    Java異常分類(lèi)以及幾種處理機(jī)制分析講解

    在Java的廣闊宇宙中,有一群特殊的“超級(jí)英雄”,它們?cè)诖a世界中穿梭,守護(hù)著程序的正常運(yùn)行——它們就是“異?!?這些英雄們,各司其職,保護(hù)著程序免受錯(cuò)誤的侵?jǐn)_,今天,我們將深入這個(gè)神秘的世界,全面解析異常的分類(lèi),掌握異常的處理機(jī)制
    2024-07-07
  • 如何讓@EnableConfigurationProperties的值注入到@Value中

    如何讓@EnableConfigurationProperties的值注入到@Value中

    這篇文章主要介紹了如何讓@EnableConfigurationProperties的值注入到@Value中的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-06-06
  • Java中典型的內(nèi)存泄露問(wèn)題和解決方法

    Java中典型的內(nèi)存泄露問(wèn)題和解決方法

    這篇文章主要介紹了Java中典型的內(nèi)存泄露問(wèn)題和解決方法,典型的內(nèi)存泄露例子是一個(gè)沒(méi)有實(shí)現(xiàn)hasCode和 equals方法的Key類(lèi)在HashMap中保存的情況,可以通過(guò)實(shí)現(xiàn)Key類(lèi)的equals和hasCode方法解決這種內(nèi)存泄漏問(wèn)題,需要的朋友可以參考下
    2014-04-04
  • Java中設(shè)置session超時(shí)(失效)的三種方法

    Java中設(shè)置session超時(shí)(失效)的三種方法

    這篇文章主要介紹了Java中設(shè)置session超時(shí)(失效)的三種方法,本文講解了在web容器中設(shè)置、在工程的web.xml中設(shè)置、通過(guò)java代碼設(shè)置3種方法,需要的朋友可以參考下
    2015-07-07
  • java多線程中的生產(chǎn)者和消費(fèi)者隊(duì)列詳解

    java多線程中的生產(chǎn)者和消費(fèi)者隊(duì)列詳解

    這篇文章主要介紹了java多線程中的生產(chǎn)者和消費(fèi)者隊(duì)列詳解,隊(duì)列,是一種數(shù)據(jù)結(jié)構(gòu),除了優(yōu)先級(jí)隊(duì)列和LIFO隊(duì)列外,隊(duì)列都是以FIFO(先進(jìn)先出)的方式對(duì)各個(gè)元素進(jìn)行排序的,需要的朋友可以參考下
    2024-01-01
  • SpringBoot+MyBatisPlus+Vue 前后端分離項(xiàng)目快速搭建過(guò)程(前端篇)

    SpringBoot+MyBatisPlus+Vue 前后端分離項(xiàng)目快速搭建過(guò)程(前端篇)

    這篇文章主要介紹了SpringBoot+MyBatisPlus+Vue 前后端分離項(xiàng)目快速搭建過(guò)程(前端篇),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-05-05
  • 利用反射獲取Java類(lèi)中的靜態(tài)變量名及變量值的簡(jiǎn)單實(shí)例

    利用反射獲取Java類(lèi)中的靜態(tài)變量名及變量值的簡(jiǎn)單實(shí)例

    下面小編就為大家?guī)?lái)一篇利用反射獲取Java類(lèi)中的靜態(tài)變量名及變量值的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-12-12

最新評(píng)論

绥棱县| 大丰市| 富平县| 延津县| 彝良县| 鄂尔多斯市| 大荔县| 永安市| 旺苍县| 巴南区| 舞钢市| 彭泽县| 阳谷县| 淮安市| 乌兰浩特市| 沾化县| 长武县| 靖安县| 恩施市| 临猗县| 攀枝花市| 罗山县| 阜新市| 祥云县| 濮阳市| 辰溪县| 紫阳县| 吕梁市| 台前县| 肇东市| 芒康县| 青岛市| 织金县| 奎屯市| 玛纳斯县| 襄城县| 萨迦县| 民和| 门源| 子洲县| 格尔木市|