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

Java中的 AtomicReference類概覽及實現(xiàn)方案

 更新時間:2025年09月15日 12:01:39   作者:探索java  
在Java開發(fā)中,常常需要構(gòu)建無鎖的應(yīng)用程序,以實現(xiàn)高性能的并發(fā)控制,本文給大家介紹Java中的AtomicReference類概覽及實現(xiàn)方案,感興趣的朋友跟隨小編一起看看吧

一、引言

在 Java 開發(fā)中,常常需要構(gòu)建無鎖的應(yīng)用程序,以實現(xiàn)高性能的并發(fā)控制。AtomicReference 就是它們中極其重要的一員。作為一種基于 CAS 機(jī)制實現(xiàn)的原實性工具,它在構(gòu)建無鎖隊列、單例、上下文切換等場景中有著重要地位。

本文將隨著一個體系化的進(jìn)程,從基本概念到源碼分析,展示 AtomicReference 在實際中如何做到 "精精不苦無鎖同步"。

二、AtomicReference 概覽

2.1 概念介紹

AtomicReference 是一個對應(yīng)任意對象的原實性工具類,繼承自 java.util.concurrent.atomic.AtomicReference<T>,提供類似于基本型的 atomicXXX 類,但對象化。

它內(nèi)部基于 Unsafe 的 CAS 操作,能夠精確地實現(xiàn)與目標(biāo)對象的引用替換。

2.2 類結(jié)構(gòu)快覽

public class AtomicReference<V> implements java.io.Serializable {
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;
    private volatile V value;
    // ... 重點(diǎn)方法看后續(xù)
}

類中主要是一個 volatile 字段 value,和基于 Unsafe 的 CAS 操作支持。

三、核心概念

3.1 CAS 原理

CAS(Compare-And-Swap)是一種無鎖的原實性操作機(jī)制,其核心是把當(dāng)前值和預(yù)期值比較,如果相等,則更新為新值。

實現(xiàn)簡化為:

boolean compareAndSet(V expect, V update) {
    if (value == expect) {
        value = update;
        return true;
    } else {
        return false;
    }
}

實際中這個操作是依賴硬件持有的原實性 CPU 指令來完成的,在 Java 中通過 Unsafe 來調(diào)用。

3.2 Unsafe 類

Unsafe 是一個本地級類,提供相當(dāng)不安全的內(nèi)核操作,包括直接操作內(nèi)存,操作類的內(nèi)部字段值等。

四、AtomicReference 的基礎(chǔ)用法

4.1 創(chuàng)建和基本操作

public class AtomicReferenceDemo {
    public static void main(String[] args) {
        AtomicReference<String> ref = new AtomicReference<>("initial");
        boolean updated = ref.compareAndSet("initial", "updated");
        System.out.println("Update successful: " + updated);
        System.out.println("Current value: " + ref.get());
    }
}

輸出:

Update successful: true
Current value: updated

五、源碼深度解析

在深入理解 AtomicReference 的行為機(jī)制之前,有必要從源碼級別進(jìn)行一層層剖析。本章節(jié)將覆蓋類結(jié)構(gòu)、關(guān)鍵方法、內(nèi)存語義以及 Unsafe.compareAndSwapObject 方法的底層實現(xiàn)。

5.1 類定義與字段分析

源碼路徑:java.util.concurrent.atomic.AtomicReference

public class AtomicReference<V> implements java.io.Serializable {
    private static final long serialVersionUID = -1848883965231344442L;
    // Unsafe 是用于執(zhí)行底層 CAS 操作的核心類
    private static final sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
    // 用于存儲 value 字段的偏移量,在初始化時通過反射獲取
    private static final long valueOffset;
    // 關(guān)鍵字段,volatile 保證可見性
    private volatile V value;
    static {
        try {
            // valueOffset 的計算,核心反射操作
            valueOffset = unsafe.objectFieldOffset
                (AtomicReference.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    public AtomicReference(V initialValue) {
        value = initialValue;
    }
    public AtomicReference() {
    }

? 說明:

  • value 是被保護(hù)的實際引用,必須是 volatile,以確保在并發(fā)線程之間可見。
  • valueOffset 是通過反射拿到的 value 字段在對象內(nèi)存結(jié)構(gòu)中的偏移量。
  • 所有 CAS 操作都基于 valueOffset。

5.2 核心方法解析

public final boolean compareAndSet(V expect, V update) {
    return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
public final void set(V newValue) {
    value = newValue;
}
public final void lazySet(V newValue) {
    unsafe.putOrderedObject(this, valueOffset, newValue);
}
public final V get() {
    return value;
}
public final V getAndSet(V newValue) {
    while (true) {
        V current = get();
        if (compareAndSet(current, newValue))
            return current;
    }
}

方法說明:

  • compareAndSet: 基于 CAS 的原子條件更新,是核心方法。
  • set: 普通賦值操作,具備 volatile 語義。
  • lazySet: 有序?qū)懭?,適用于延遲可見的情況,性能更優(yōu)。
  • getAndSet: 實現(xiàn)方式為循環(huán) CAS。

5.3 內(nèi)存語義分析

  • volatile 語義:保證讀寫操作的可見性,防止指令重排。
  • compareAndSet 的語義:具備 volatile 的讀+寫語義,同時含有內(nèi)存屏障(full fence)。
  • lazySet 語義:具備“store-store barrier”,只保證新值最終會被線程看到,但不強(qiáng)制立即生效。

內(nèi)存屏障說明:

compareAndSet:
  LoadLoad + LoadStore + StoreStore + StoreLoad(全屏障)
lazySet:
  StoreStore(寫屏障)

這也是為什么在高并發(fā)但不要求嚴(yán)格即時可見性的場景下,lazySet 更高效。

5.4 Unsafe.compareAndSwapObject 深度剖析

該方法定義如下:

public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);

其是 native 方法,最終調(diào)用 JVM 內(nèi)部封裝的 CPU 指令實現(xiàn)(如 x86 架構(gòu)下的 CMPXCHG)。其關(guān)鍵邏輯:

  • 比較對象 o 中偏移量為 offset 的字段值是否等于 expected
  • 如果相等,則用 x 替換原值,返回 true
  • 否則不做修改,返回 false

?? 實質(zhì):此操作具備原子性,不會被線程上下文切換打斷。

CPU 層級說明(以 x86 為例)

在底層,JVM 會借助 CPU 提供的原子指令實現(xiàn)上述邏輯,比如:

lock cmpxchg r/m32, r32  // 帶鎖的比較交換,保證總線級別原子

這確保了在多核環(huán)境中即使多個線程同時競爭更新,依然可以避免數(shù)據(jù)競爭。

5.5 JVM 字節(jié)碼觀察

我們通過 javap -c -v 查看 compareAndSet 調(diào)用層次:

javap -c -v java.util.concurrent.atomic.AtomicReference

輸出片段如下:

  public final boolean compareAndSet(java.lang.Object, java.lang.Object);
    Code:
       0: getstatic     #16                 // Field unsafe:Lsun/misc/Unsafe;
       3: aload_0
       4: getstatic     #18                 // Field valueOffset:J
       7: aload_1
       8: aload_2
       9: invokevirtual #24                 // Method sun/misc/Unsafe.compareAndSwapObject
      12: ireturn

從字節(jié)碼角度也能看出 compareAndSet 調(diào)用是對 Unsafe 對象方法的直接轉(zhuǎn)發(fā)。

小結(jié)

  • AtomicReference 實現(xiàn)基于 Unsafe 的 CAS 操作,繞過 synchronized 實現(xiàn)高性能原子更新。
  • valueOffset 是通過反射獲取的內(nèi)存偏移,用于精確定位對象字段。
  • compareAndSet 調(diào)用的是 JVM 層原子指令(cmpxchg),確保并發(fā)安全。
  • volatilelazySet 提供不同程度的內(nèi)存可見性策略,需根據(jù)具體業(yè)務(wù)場景選擇。

六、常見問題及解決方案

AtomicReference 雖然為無鎖編程提供了便捷手段,但在實踐中仍然存在若干值得注意的問題。特別是在高并發(fā)環(huán)境下,如果理解不當(dāng),可能會引入隱蔽的并發(fā) bug。本章節(jié)總結(jié)了實際使用中遇到的典型問題及對應(yīng)解決策略。

6.1 問題一:ABA 問題

問題描述:

CAS 操作基于對象的引用地址進(jìn)行比較,若地址值相同則視為“未變”,這就帶來一個典型并發(fā)陷阱:ABA 問題。

定義:

線程 A 讀取變量為 A,線程 B 將其從 A 改為 B 再改回 A,線程 A 發(fā)現(xiàn)當(dāng)前還是 A,于是操作成功,但其實已經(jīng)發(fā)生過變化。

示例:

AtomicReference<String> ref = new AtomicReference<>("A");
Thread t1 = new Thread(() -> {
    String prev = ref.get(); // 讀取到 A
    sleep(100);
    boolean success = ref.compareAndSet(prev, "C");
    System.out.println("T1 CAS: " + success); // 可能為 true,但實際中間已經(jīng)被改動過
});
Thread t2 = new Thread(() -> {
    ref.compareAndSet("A", "B");
    ref.compareAndSet("B", "A");
});
t1.start();
t2.start();

風(fēng)險:

雖然最終值為 "A",但實際上經(jīng)歷了變化。CAS 操作未感知這些中間變更,可能導(dǎo)致數(shù)據(jù)一致性問題。

解決方案:AtomicStampedReference

為了解決 ABA 問題,JDK 提供了 AtomicStampedReference 類。它不僅保存值,還維護(hù)一個版本號(stamp),每次更新都需同時更新 stamp,從而感知變量是否真正變化過。

示例:

AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);
Thread t1 = new Thread(() -> {
    int[] stamp = new int[1];
    String prev = ref.get(stamp);
    sleep(100);
    boolean success = ref.compareAndSet(prev, "C", stamp[0], stamp[0] + 1);
    System.out.println("T1 CAS with stamp: " + success);
});
Thread t2 = new Thread(() -> {
    int[] stamp = new int[1];
    String curr = ref.get(stamp);
    ref.compareAndSet(curr, "B", stamp[0], stamp[0] + 1);
    ref.compareAndSet("B", "A", stamp[0] + 1, stamp[0] + 2);
});
t1.start();
t2.start();

? 由于 stamp 不同,即使值回到 "A",也能檢測到版本不一致,防止 ABA 問題。

6.2 問題二:引用本身原子,不代表對象狀態(tài)原子

AtomicReference<T> 僅保證對象引用的更新是原子的,并不能保證引用對象內(nèi)部的字段或狀態(tài)是線程安全的。

示例:

class User {
    String name;
    int age;
}
AtomicReference<User> ref = new AtomicReference<>(new User());
ref.get().age++; // 非原子操作

風(fēng)險:

如果多個線程同時修改 ref.get().age++,依然可能引發(fā)競態(tài)條件。

解決方案:

  • 使用 AtomicReference<User> 實現(xiàn)整體替換(不可變類方案)
  • 或封裝更新邏輯,通過 CAS 替換整個對象:
while (true) {
    User oldUser = ref.get();
    User newUser = new User();
    newUser.name = oldUser.name;
    newUser.age = oldUser.age + 1;
    if (ref.compareAndSet(oldUser, newUser)) break;
}

6.3 問題三:頻繁 CAS 導(dǎo)致性能下降

CAS 是樂觀鎖思想,但在高競爭場景下,多次失敗會導(dǎo)致性能問題。

解決策略:

  • 使用 LongAdderStampedLock 等替代方案
  • 或者使用回退策略、自旋上限等優(yōu)化手段

小結(jié)

問題現(xiàn)象解決方式
ABA 問題值恢復(fù)原樣但中途被修改使用 AtomicStampedReference
引用更新原子但狀態(tài)不安全內(nèi)部字段可能并發(fā)讀寫沖突使用不可變對象整體替換
CAS 自旋性能差多線程競爭失敗導(dǎo)致 CPU 消耗上升增加退避策略 / 限制自旋次數(shù)

在實際應(yīng)用中,合理選擇原子類并避免過度依賴單一機(jī)制是保障系統(tǒng)健壯性的關(guān)鍵。

到此這篇關(guān)于Java 中的 AtomicReference 類及其實現(xiàn)的文章就介紹到這了,更多相關(guān)Java AtomicReference 類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中的單向鏈表詳解

    Java中的單向鏈表詳解

    這篇文章主要介紹了Java中的單向鏈表詳解,單向鏈表又叫單鏈表,是鏈表的一種,由節(jié)點(diǎn)構(gòu)成,head指針指向第一個稱為表頭節(jié)點(diǎn),而終止指向最后一個null指針,需要的朋友可以參考下
    2024-01-01
  • java如何給指定類配置單獨(dú)的日志文件輸出

    java如何給指定類配置單獨(dú)的日志文件輸出

    這篇文章主要介紹了java如何給指定類配置單獨(dú)的日志文件輸出問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • java?Springboot實現(xiàn)教務(wù)管理系統(tǒng)

    java?Springboot實現(xiàn)教務(wù)管理系統(tǒng)

    這篇文章主要介紹了java?Springboot實現(xiàn)教務(wù)管理系統(tǒng)的過程,文章圍繞實現(xiàn)過程展開全文詳細(xì)內(nèi)容,具有一定的參考價值,需要的朋友可以參考一下,希望對你有所幫助
    2021-11-11
  • SpringBoot中的JPA(Java?Persistence?API)詳解

    SpringBoot中的JPA(Java?Persistence?API)詳解

    這篇文章主要介紹了SpringBoot中的JPA(Java?Persistence?API)詳解,JPA用于將?Java?對象映射到關(guān)系型數(shù)據(jù)庫中,它提供了一種面向?qū)ο蟮姆绞絹聿僮鲾?shù)據(jù)庫,使得開發(fā)者可以更加方便地進(jìn)行數(shù)據(jù)持久化操作,需要的朋友可以參考下
    2023-07-07
  • Java事務(wù)@Transactional?、@GlobalTransactional使用步驟

    Java事務(wù)@Transactional?、@GlobalTransactional使用步驟

    這篇文章主要介紹了使用@Transactional和@GlobalTransactional注解進(jìn)行事務(wù)管理的區(qū)別和應(yīng)用場景,@Transactional用于單個服務(wù)內(nèi)的本地事務(wù)管理,而@GlobalTransactional用于跨服務(wù)的分布式事務(wù)管理,文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下
    2025-05-05
  • 寶塔升級JDK版本超詳細(xì)圖文教程

    寶塔升級JDK版本超詳細(xì)圖文教程

    寶塔自動安裝的JDK是一種用于開發(fā)和運(yùn)行Java程序的軟件開發(fā)工具包,下面這篇文章主要給大家介紹了關(guān)于寶塔升級JDK版本的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • 使用BigInteger實現(xiàn)除法取余

    使用BigInteger實現(xiàn)除法取余

    這篇文章主要介紹了使用BigInteger實現(xiàn)除法取余操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • JDK多版本管理工具安裝和使用詳細(xì)教程

    JDK多版本管理工具安裝和使用詳細(xì)教程

    隨著軟件開發(fā)環(huán)境的日益復(fù)雜,多版本Java開發(fā)工具包(JDK)管理變得尤為重要,下面這篇文章主要介紹了JDK多版本管理工具安裝和使用的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-09-09
  • Java中Minio的基本使用詳解

    Java中Minio的基本使用詳解

    這篇文章主要介紹了Java中Minio的基本使用詳解,MinIO 是一個基于Apache License v2.0開源協(xié)議的對象存儲服務(wù),它兼容亞馬遜S3云存儲服務(wù)接口,非常適合于存儲大容量非結(jié)構(gòu)化的數(shù)據(jù),例如圖片、視頻、日志文件、備份數(shù)據(jù)和容器/虛擬機(jī)鏡像等,需要的朋友可以參考下
    2024-01-01
  • 基于Javamail實現(xiàn)發(fā)送郵件(QQ/網(wǎng)易郵件服務(wù)器)

    基于Javamail實現(xiàn)發(fā)送郵件(QQ/網(wǎng)易郵件服務(wù)器)

    這篇文章主要介紹了基于Javamail實現(xiàn)發(fā)送郵件,分別使用QQ郵箱作為smtp郵件服務(wù)器發(fā)送郵件,使用網(wǎng)易郵箱作為smtp郵件服務(wù)器發(fā)送郵件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08

最新評論

镇宁| 岐山县| 井陉县| 板桥市| 塘沽区| 莱西市| 南雄市| 普定县| 绥江县| 马关县| 湘潭县| 故城县| 鄂温| 铁岭市| 河源市| 徐水县| 仁寿县| 丰都县| 吴桥县| 新龙县| 青海省| 济源市| 玉龙| 裕民县| 荥阳市| 临邑县| 石柱| 商洛市| 桑植县| 弥渡县| 长治市| 建平县| 平顺县| 天柱县| 安平县| 朝阳市| 衡南县| 许昌市| 安吉县| 福清市| 望奎县|