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

Java中的volatile關(guān)鍵字經(jīng)典應(yīng)用場(chǎng)景和常見(jiàn)問(wèn)題

 更新時(shí)間:2026年03月03日 08:35:13   作者:身如柳絮隨風(fēng)揚(yáng)  
這篇文章主要介紹了Java中volatile關(guān)鍵字經(jīng)典應(yīng)用場(chǎng)景和常見(jiàn)問(wèn)題的相關(guān)資料,volatile是一種輕量級(jí)鎖的實(shí)現(xiàn),它針對(duì)的僅僅是共享變量,不會(huì)對(duì)線程加鎖,更不會(huì)造成線程的阻塞,需要的朋友可以參考下

一、概述

volatile 是 Java 中用于修飾變量的關(guān)鍵字,它提供了一種輕量級(jí)的線程間通信機(jī)制。與 synchronized 相比,volatile 不會(huì)引起線程上下文切換和調(diào)度,因此性能開銷更小。然而,其同步能力有限,使用不當(dāng)容易產(chǎn)生線程安全問(wèn)題。

二、核心特性

1.可見(jiàn)性保證(Visibility)

  • 當(dāng)某個(gè)線程修改 volatile 變量的值時(shí),該值會(huì)立即被強(qiáng)制刷新到主內(nèi)存
  • 其他線程讀取該變量時(shí),會(huì)從主內(nèi)存重新加載最新值,而非使用本地線程緩存
  • 解決了多線程環(huán)境下因 CPU 緩存導(dǎo)致的數(shù)據(jù)不一致問(wèn)題

2.有序性保證(Ordering)

  • 禁止編譯器和處理器對(duì) volatile 變量的讀寫操作進(jìn)行指令重排序
  • 確保:
    • volatile 寫操作之前的任何讀寫操作不會(huì)被重排序到寫之后
    • volatile 讀操作之后的任何讀寫操作不會(huì)被重排序到讀之前
  • 建立 happens-before 關(guān)系,確保多線程間的操作順序可見(jiàn)性

3.不保證原子性(Non-Atomicity)

  • volatile 無(wú)法保證復(fù)合操作的原子性(如 i++
  • 復(fù)合操作由多個(gè)步驟組成,中間可能被其他線程中斷

三、內(nèi)存語(yǔ)義

volatile 寫操作的內(nèi)存屏障

[普通寫/讀操作]  →  [StoreStore屏障]  →  [volatile寫]  →  [StoreLoad屏障]

volatile 讀操作的內(nèi)存屏障

[volatile讀]  →  [LoadLoad屏障]  →  [LoadStore屏障]  →  [普通寫/讀操作]

內(nèi)存屏障的作用:

  1. StoreStore屏障:確保 volatile 寫之前的普通寫操作已刷新到主內(nèi)存
  2. StoreLoad屏障:確保 volatile 寫完成后,后續(xù)的讀操作能看到所有之前的寫入
  3. LoadLoad屏障:確保 volatile 讀之后的操作不會(huì)被重排序到讀之前
  4. LoadStore屏障:確保 volatile 讀之后的寫操作不會(huì)被重排序到讀之前

四、經(jīng)典應(yīng)用場(chǎng)景

1.狀態(tài)標(biāo)志(最常用)

public class ShutdownHandler {
    private volatile boolean shutdownRequested = false;
    
    public void shutdown() {
        shutdownRequested = true;
    }
    
    public void doWork() {
        while (!shutdownRequested) {
            // 執(zhí)行任務(wù)
        }
    }
}

2.雙重檢查鎖定單例模式(DCL)

public class Singleton {
    // 必須使用 volatile 防止指令重排序
    private static volatile Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {                     // 第一次檢查:避免不必要的同步
            synchronized (Singleton.class) {
                if (instance == null) {             // 第二次檢查:確保單例
                    // 創(chuàng)建對(duì)象分為三步(無(wú)volatile可能重排序):
                    // 1. 分配內(nèi)存空間
                    // 2. 初始化對(duì)象
                    // 3. 將引用指向內(nèi)存地址
                    // volatile 確保 2 在 3 之前完成
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

3.一次性安全發(fā)布(One-Time Safe Publication)

public class Resource {
    private volatile Resource resource;
    
    public Resource getResource() {
        if (resource == null) {
            synchronized (this) {
                if (resource == null) {
                    resource = new Resource();
                }
            }
        }
        return resource;
    }
}

4.獨(dú)立觀察(Independent Observation)

public class SensorReader {
    private volatile double currentTemperature;
    
    // 一個(gè)線程定期更新溫度
    public void updateTemperature(double temp) {
        currentTemperature = temp;
    }
    
    // 多個(gè)線程同時(shí)讀取最新的溫度值
    public double getTemperature() {
        return currentTemperature;
    }
}

五、volatile與synchronized詳細(xì)對(duì)比

特性volatilesynchronized
原子性僅保證單個(gè)讀/寫操作的原子性
不保證復(fù)合操作(如 i++)的原子性
保證整個(gè)代碼塊/方法的原子性
可見(jiàn)性保證變量對(duì)所有線程立即可見(jiàn)保證變量對(duì)所有線程可見(jiàn)
有序性禁止指令重排序
(通過(guò)內(nèi)存屏障實(shí)現(xiàn))
保證有序性
(但允許同步塊內(nèi)重排序)
阻塞性非阻塞機(jī)制
線程不會(huì)掛起
阻塞機(jī)制
獲取不到鎖的線程會(huì)掛起等待
性能輕量級(jí),性能開銷小
(僅內(nèi)存屏障開銷)
重量級(jí),性能開銷較大
(涉及鎖競(jìng)爭(zhēng)、上下文切換)
作用范圍變量級(jí)別代碼塊或方法級(jí)別
適用場(chǎng)景狀態(tài)標(biāo)志、一次性發(fā)布復(fù)雜同步邏輯、需要原子性的復(fù)合操作

六、常見(jiàn)誤區(qū)與注意事項(xiàng)

錯(cuò)誤示例:誤以為 volatile 能保證原子性

public class Counter {
    private volatile int count = 0;
    
    // 線程不安全!count++ 不是原子操作
    public void increment() {
        count++;  // 實(shí)際包含:讀 → 加1 → 寫 三個(gè)步驟
    }
}

正確解決方案

// 方案1:使用 synchronized(適合復(fù)雜同步)
public class SynchronizedCounter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;
    }
}

// 方案2:使用原子類(推薦,性能更好)
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicCounter {
    private AtomicInteger count = new AtomicInteger(0);
    
    public void increment() {
        count.incrementAndGet();  // CAS操作,保證原子性
    }
    
    public int getCount() {
        return count.get();
    }
}

// 方案3:使用 volatile + CAS(高級(jí)用法)
public class VolatileCASCounter {
    private volatile int count = 0;
    private static final sun.misc.Unsafe UNSAFE = // 獲取Unsafe實(shí)例
    
    public void increment() {
        int current;
        do {
            current = count;
        } while (!UNSAFE.compareAndSwapInt(this, OFFSET, current, current + 1));
    }
}

使用建議總結(jié)

  1. 優(yōu)先考慮不可變對(duì)象:避免使用 volatile,設(shè)計(jì)為不可變對(duì)象
  2. 一個(gè)寫線程,多個(gè)讀線程:典型的 volatile 適用場(chǎng)景
  3. 變量不參與不變性約束volatile 變量不應(yīng)依賴于其他變量,也不應(yīng)被其他變量依賴
  4. 替代方案優(yōu)先:考慮使用 java.util.concurrent.atomic 包下的原子類
  5. 謹(jǐn)慎使用:只在明確理解其語(yǔ)義的場(chǎng)景下使用

七、與 JMM(Java內(nèi)存模型)的關(guān)系

volatile 變量的讀寫操作建立了 happens-before 關(guān)系:

  • 對(duì) volatile 變量的寫操作 happens-before 于后續(xù)對(duì)該變量的讀操作
  • 這與 synchronized 的釋放鎖 happens-before 于獲取鎖的語(yǔ)義類似

八、性能考量

性能測(cè)試對(duì)比

// volatile 變量訪問(wèn) vs 普通變量訪問(wèn)
volatile int vCounter = 0;
int counter = 0;

// volatile 訪問(wèn)有約10-20%的性能損耗
// 但相比 synchronized 的數(shù)千倍性能損耗可忽略不計(jì)

最佳實(shí)踐

  1. 避免過(guò)度使用:不必要的 volatile 修飾會(huì)增加內(nèi)存屏障開銷
  2. 結(jié)合使用volatile 適合與 final 結(jié)合,用于安全發(fā)布
  3. 替代方案:考慮使用 ThreadLocal 避免共享變量

九、擴(kuò)展知識(shí):volatile 在 JSR-133 中的增強(qiáng)

在 Java 5 之前,volatile 只保證可見(jiàn)性,不保證有序性。JSR-133(Java內(nèi)存模型修訂)強(qiáng)化了 volatile 的語(yǔ)義,通過(guò)內(nèi)存屏障同時(shí)保證了可見(jiàn)性和有序性。

十、總結(jié)

volatile 是 Java 并發(fā)編程中的重要工具,但理解其局限性至關(guān)重要:

適合使用 volatile 的場(chǎng)景:

  • 狀態(tài)標(biāo)志位(一個(gè)線程寫,多個(gè)線程讀)
  • 一次性安全發(fā)布(如單例模式的DCL實(shí)現(xiàn))
  • 獨(dú)立觀察(如傳感器數(shù)據(jù)讀?。?/li>

不適合使用 volatile 的場(chǎng)景:

  • 需要原子性的復(fù)合操作
  • 變量參與不變性約束
  • 依賴其他變量的計(jì)算

黃金法則: 當(dāng)您不確定是否需要使用 volatile 時(shí),優(yōu)先考慮使用更高層次的并發(fā)工具(如 java.util.concurrent 包中的類),這些工具通常封裝了更安全、更高效的并發(fā)實(shí)現(xiàn)。

到此這篇關(guān)于Java中volatile關(guān)鍵字經(jīng)典應(yīng)用場(chǎng)景和常見(jiàn)問(wèn)題的文章就介紹到這了,更多相關(guān)Java中volatile關(guān)鍵字內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Nacos源碼閱讀方法

    Nacos源碼閱讀方法

    這篇文章將會(huì)帶大家閱讀Nacos源碼以及教大家閱讀源碼的技巧,感興趣的朋友跟隨小編一起看看Nacos源碼閱讀方法
    2022-03-03
  • SpringBoot詳細(xì)講解斷言機(jī)制原理

    SpringBoot詳細(xì)講解斷言機(jī)制原理

    斷言Assertion是測(cè)試方法中的核心部分,用來(lái)對(duì)測(cè)試需要滿足的條件進(jìn)行驗(yàn)證。這些斷言方法都是org.junit.jupiter.api.Assertions的靜態(tài)方法。檢查業(yè)務(wù)邏輯返回的數(shù)據(jù)是否合理。所有的測(cè)試運(yùn)行結(jié)束以后,會(huì)有一個(gè)詳細(xì)的測(cè)試報(bào)告
    2022-06-06
  • SpringBoot中的@ConfigurationProperties注解解析

    SpringBoot中的@ConfigurationProperties注解解析

    這篇文章主要介紹了SpringBoot中的@ConfigurationProperties注解解析,Spring源碼中大量使用了ConfigurationProperties注解,通過(guò)與其他注解配合使用,能夠?qū)崿F(xiàn)Bean的按需配置,該注解可以放在類上,也可以放在方法上,需要的朋友可以參考下
    2023-11-11
  • SpringBoot使用Validation實(shí)現(xiàn)接口校驗(yàn)的超全使用指南

    SpringBoot使用Validation實(shí)現(xiàn)接口校驗(yàn)的超全使用指南

    這篇文章主要為大家詳細(xì)介紹了SpringBoot使用Validation實(shí)現(xiàn)接口校驗(yàn)的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2026-03-03
  • Java解析XML文件開源庫(kù)DOM4J

    Java解析XML文件開源庫(kù)DOM4J

    dom4j是一個(gè)Java的XML API,是jdom的升級(jí)品,用來(lái)讀寫XML文件的。dom4j是一個(gè)十分優(yōu)秀的JavaXML API,具有性能優(yōu)異、功能強(qiáng)大和極其易使用的特點(diǎn),它的性能超過(guò)sun公司官方的dom技術(shù),同時(shí)它也是一個(gè)開放源代碼的軟件
    2023-01-01
  • Java中for與foreach的區(qū)別

    Java中for與foreach的區(qū)別

    本文主要介紹了Java中for與foreach的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • SpringBoot如何從配置文件中讀取配置參數(shù)

    SpringBoot如何從配置文件中讀取配置參數(shù)

    這篇文章主要介紹了SpringBoot如何從配置文件中讀取配置參數(shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 為什么Java要把字符串設(shè)計(jì)成不可變的

    為什么Java要把字符串設(shè)計(jì)成不可變的

    為什么Java要把字符串設(shè)計(jì)成不可變的,這篇文章給出了Java字符串設(shè)計(jì)成不可變的原因,感興趣的小伙伴們可以參考一下
    2017-06-06
  • idea項(xiàng)目的左側(cè)目錄沒(méi)了如何設(shè)置

    idea項(xiàng)目的左側(cè)目錄沒(méi)了如何設(shè)置

    這篇文章主要介紹了idea項(xiàng)目的左側(cè)目錄沒(méi)了如何設(shè)置的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • Java中進(jìn)程與線程的區(qū)別

    Java中進(jìn)程與線程的區(qū)別

    這篇文章主要介紹了Java進(jìn)程與線程的區(qū)別,進(jìn)程(Process)是操作系統(tǒng)分配資源的基本單位,線程(Thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的基本單位,下文更多兩者區(qū)別。需要的小伙伴可以參考一下
    2022-05-05

最新評(píng)論

华亭县| 花莲县| 翼城县| 余姚市| 崇阳县| 通山县| 贵溪市| 安新县| 卓尼县| 和静县| 石首市| 信丰县| 石林| 舒兰市| 秀山| 五峰| 古蔺县| 慈溪市| 疏附县| 洪江市| 虎林市| 平罗县| 江山市| 出国| 六枝特区| 喜德县| 左权县| 禹州市| 鲁甸县| 茶陵县| 清河县| 罗源县| 陕西省| 淳安县| 遂宁市| 马公市| 三河市| 衢州市| 漳州市| 清远市| 荥经县|