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

Java CAS原理和用法總結

 更新時間:2026年01月12日 09:24:30   作者:看透也說透kevin  
CAS(Compare And Swap)是一種無鎖的原子操作機制,通過一條CPU硬件指令(如x86架構的CMPXCHG指令)實現(xiàn),能保證操作的原子性,本文給大家介紹java CAS原理和用法,感興趣的朋友跟隨小編一起看看吧

一、CAS 原理

1. 核心思想

CAS 是一種無鎖的原子操作機制。它的核心思想是:我認為值應該是A,如果是,那我就把它改成B;如果不是A(說明被別人改過了),那我就不修改,然后可以選擇重試或放棄。

這個操作是作為一條CPU硬件指令實現(xiàn)的(在x86架構上是 CMPXCHG 指令),因此它能保證原子性,不會被線程調度打斷。

2. 操作模型

CAS 操作涉及三個操作數:

  • 內存位置(V)
  • 預期的原值(A)
  • 新值(B)

偽代碼邏輯如下:

if (V == A) {
V = B;
return true;
} else {
return false;
}

但關鍵是,整個比較和交換的過程是一個不可分割的原子操作。

3. 工作流程

當一個線程想要更新一個變量時,它會:

  1. 獲取當前內存中的值,作為期望值 A。
  2. 計算出新值 B
  3. 執(zhí)行 CAS 指令,判斷當前內存中的值是否還是 A。
    • 如果是,說明沒有其他線程修改過,成功將值更新為 B。
    • 如果不是,說明值已被其他線程修改,本次更新失敗。線程通常會重試整個操作(獲取新的當前值,計算新值,再次執(zhí)行CAS),直到成功為止。這種重試行為就是常見的自旋。

4. 優(yōu)點與缺點

  • 優(yōu)點
    • 高性能:避免了重量級鎖(如 synchronized)帶來的線程阻塞、喚醒和上下文切換的開銷,在競爭不激烈的場景下性能極高。
    • 避免死鎖:由于是無鎖操作,從根本上避免了死鎖問題。
  • 缺點
    • ABA 問題:CAS 只檢查值是否變化,但如果一個值從 A 變成 B,又被改回 A,CAS 會誤以為它沒變。解決方案是使用版本號標記(如 AtomicStampedReference)。
    • 自旋開銷:在高競爭環(huán)境下,如果線程一直失敗重試,會長時間占用 CPU,消耗資源。
    • 只能保證一個共享變量的原子操作:對于多個共享變量,CAS 無法保證原子性。但可以將它們合并成一個對象,使用 AtomicReference 來保證原子性。

二、Java 中的 CAS 用法

在 Java 中,你不能直接使用 CPU 指令。CAS 的能力是通過 sun.misc.Unsafe 類中的本地(Native)方法提供的。但通常,我們不會直接使用 Unsafe,而是使用 JD 在 java.util.concurrent.atomic 包下為我們封裝好的原子類。

1. 主要的原子類

  • 基本類型
    • AtomicInteger:整型原子類
    • AtomicLong:長整型原子類
    • AtomicBoolean:布爾型原子類
  • 數組類型
    • AtomicIntegerArray:整型數組原子類
    • AtomicLongArray:長整型數組原子類
    • AtomicReferenceArray:引用類型數組原子類
  • 引用類型
    • AtomicReference:引用類型原子類
    • AtomicMarkableReference:帶標記位的引用類型原子類(解決ABA問題的一種方式)
    • AtomicStampedReference帶版本號的引用類型原子類(解決ABA問題的標準方案)
  • 字段更新器
    • AtomicIntegerFieldUpdater:基于反射,原子性地更新某個類的 volatile int 字段。
    • AtomicLongFieldUpdater
    • AtomicReferenceFieldUpdater

2. 核心方法

所有原子類都提供了基于 CAS 的核心方法:

  • boolean compareAndSet(int expect, int update)
    • 這是最核心的方法!如果當前值等于期望值 expect,則原子地將值設置為 update,成功返回 true,失敗返回 false。
  • int getAndSet(int newValue)
    • 原子地設置為新值,并返回舊值。底層通常通過循環(huán) CAS 實現(xiàn)。
  • int getAndIncrement() / int getAndDecrement()
    • 原子地遞增/遞減 1,返回舊值。i++ 的原子版本。
  • int getAndAdd(int delta)
    • 原子地加上 delta,返回舊值。
  • int incrementAndGet() / int decrementAndGet()
    • 原子地遞增/遞減 1,返回新值。++i 的原子版本。

3. 代碼示例

示例 1:使用 AtomicInteger 實現(xiàn)線程安全的計數器

import java.util.concurrent.atomic.AtomicInteger;
public class CASDemo {
    public static void main(String[] args) throws InterruptedException {
        AtomicInteger atomicInt = new AtomicInteger(0);
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                // 內部通過循環(huán)CAS操作實現(xiàn)原子遞增
                atomicInt.incrementAndGet();
            }
        };
        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        // 結果總是 2000,保證了原子性
        System.out.println("Final Count: " + atomicInt.get()); 
    }
}

示例 2:手動使用 compareAndSet 進行自旋

AtomicInteger atomicInt = new AtomicInteger(0);
int oldValue, newValue;
do {
    oldValue = atomicInt.get(); // 獲取當前值作為預期值
    newValue = oldValue + 1;    // 計算新值
} while (!atomicInt.compareAndSet(oldValue, newValue)); 
// 如果CAS失?。╫ldValue已不是當前值),則循環(huán)重試

示例 3:使用 AtomicStampedReference 解決 ABA 問題

import java.util.concurrent.atomic.AtomicStampedReference;
public class ABADemo {
    // 初始值為 100,版本號(Stamp)為 0
    static AtomicStampedReference<Integer> atomicStampedRef = 
            new AtomicStampedReference<>(100, 0);
    public static void main(String[] args) throws InterruptedException {
        int initialStamp = atomicStampedRef.getStamp(); // 獲取初始版本號
        // 線程1模擬ABA操作
        Thread thread1 = new Thread(() -> {
            // 先改成 101,版本號+1
            atomicStampedRef.compareAndSet(100, 101, initialStamp, initialStamp + 1);
            // 再改回 100,版本號再+1
            atomicStampedRef.compareAndSet(101, 100, initialStamp + 1, initialStamp + 2);
        });
        // 線程2嘗試修改
        Thread thread2 = new Thread(() -> {
            // 先睡一會兒,確保線程1完成了ABA操作
            try { Thread.sleep(1000); } catch (InterruptedException e) {}
            // 嘗試修改。雖然期望值還是100,但版本號已經從0變成了2,所以CAS會失?。?
            boolean success = atomicStampedRef.compareAndSet(
                    100, 
                    202, 
                    initialStamp, // 傳入舊的版本號0
                    initialStamp + 1
            );
            System.out.println("CAS successful? " + success); // 輸出:false
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
    }
}

總結

特性描述
本質一條CPU原子指令,通過 Unsafe 類提供給 Java 開發(fā)者使用。
實現(xiàn)JDK 的 java.util.concurrent.atomic 包下的原子類對其進行了封裝。
核心方法compareAndSet(expectedValue, newValue)
優(yōu)點無鎖高性能(低競爭時)、避免死鎖。
缺點ABA問題(用版本號解決)、自旋CPU開銷(高競爭時)。
應用場景計數器、序列號生成器、ConcurrentHashMap 等高性能并發(fā)容器的實現(xiàn)。

CAS 是現(xiàn)代并發(fā)包(JUC)的基石,理解了它就能更好地理解 ReentrantLock、線程池等高級并發(fā)工具的內部工作原理。

到此這篇關于java CAS原理和用法的文章就介紹到這了,更多相關java CAS原理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java實現(xiàn)音樂播放器完整代碼(調整顯示音量大小、調整進度、圖片切換)

    java實現(xiàn)音樂播放器完整代碼(調整顯示音量大小、調整進度、圖片切換)

    這篇文章主要給大家介紹了關于java實現(xiàn)音樂播放器(調整顯示音量大小、調整進度、圖片切換)的相關資料,這本身是老師布置的一個作業(yè),寫完感覺不錯分享給大家,需要的朋友可以參考下
    2023-07-07
  • 三分鐘快速掌握Java中枚舉(enum)

    三分鐘快速掌握Java中枚舉(enum)

    enum的全稱為enumeration, 是 JDK 1.5中引入的新特性,存放在 java.lang包中。下面這篇文章是我在使用enum過程中的一些經驗和總結,分享出來方便大家快速的掌握Java中枚舉(enum),有需要的朋友們下面跟著小編來一起看看吧。
    2016-12-12
  • springsecurity 基本使用詳解

    springsecurity 基本使用詳解

    這篇文章主要介紹了springsecurity 基本使用,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • java中pdf轉圖片的實現(xiàn)方法

    java中pdf轉圖片的實現(xiàn)方法

    下面小編就為大家?guī)硪黄猨ava中pdf轉圖片的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • Spring?Boot如何利用攔截器加緩存完成接口防刷操作

    Spring?Boot如何利用攔截器加緩存完成接口防刷操作

    流的需求出現(xiàn)在許多常見的場景中,下面這篇文章主要給大家介紹了關于Spring?Boot如何利用攔截器加緩存完成接口防刷操作的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • 在Java中將jsonObject轉換成對象的實現(xiàn)方法

    在Java中將jsonObject轉換成對象的實現(xiàn)方法

    在現(xiàn)代的Web開發(fā)中,JSON作為一種輕量級的數據交換格式,因其易讀性和易于解析的特點而被廣泛使用,本文將介紹如何在Java中將??jsonObject??轉換成Java對象,主要通過使用Gson庫來實現(xiàn)這一功能,需要的朋友可以參考下
    2025-04-04
  • SpringBoot參數驗證10個技巧值得收藏

    SpringBoot參數驗證10個技巧值得收藏

    Spring Boot提供了內置的驗證注解,可以幫助簡單、快速地對輸入字段進行驗證,例如檢查 null 或空字段、強制執(zhí)行長度限制、使用正則表達式驗證模式以及驗證電子郵件地址,那么在Spring Boot應用中如何做好參數校驗工作呢,本文提供了10個小技巧感興趣的朋友一起看看吧
    2023-08-08
  • 聊聊Java中接口重試機制的幾種解決方案

    聊聊Java中接口重試機制的幾種解決方案

    接口請求重試機制是保證系統(tǒng)穩(wěn)定性和容錯能力的重要手段之一,當接口請求發(fā)生失敗或暫時性錯誤時,通過重試機制可以提高請求的成功率,本文將詳細介紹接口請求重試機制的幾種常見方法,感興趣的可以了解一下
    2025-07-07
  • 使用Mybatis生成樹形菜單的方法詳解

    使用Mybatis生成樹形菜單的方法詳解

    開發(fā)中我們難免會遇到各種樹形結構展示的場景,比如用戶登錄系統(tǒng)后菜單的展示等,本文為大家整理了使用Mybatis生成樹形菜單的方法,感興趣的小伙伴可以了解一下
    2023-06-06
  • 詳解Spring Boot 配置加載順序及屬性加載順序

    詳解Spring Boot 配置加載順序及屬性加載順序

    這篇文章主要介紹了詳解Spring Boot 配置加載順序及屬性加載順序,本章內容基于 Spring Boot 2.0 進行詳解,感興趣的朋友跟隨腳本之家小編一起看看吧
    2018-08-08

最新評論

泽库县| 商洛市| 河北省| 贵州省| 定兴县| 克什克腾旗| 乃东县| 额尔古纳市| 大悟县| 蓝田县| 教育| 宜兰县| 苏尼特左旗| 彰武县| 诏安县| 静宁县| 冷水江市| 郑州市| 阳原县| 波密县| 石屏县| 乡城县| 柳州市| 伊金霍洛旗| 托克逊县| 昌平区| 维西| 洪江市| 顺昌县| 武川县| 甘谷县| 八宿县| 襄樊市| 汉中市| 平顶山市| 西峡县| 视频| 平和县| 左贡县| 宜兰市| 浮梁县|