日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一文读懂 volatile 关键字

發(fā)布時(shí)間:2025/3/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一文读懂 volatile 关键字 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

??點(diǎn)擊上方?好好學(xué)java?,選擇?星標(biāo)?公眾號(hào)

重磅資訊、干貨,第一時(shí)間送達(dá) 今日推薦:有了這 4 款工具,老板再也不怕我寫爛SQL了個(gè)人原創(chuàng)+1博客:點(diǎn)擊前往,查看更多 作者:對(duì)弈 來源:https://www.cnblogs.com/MessiXiaoMo3334/p/12615823.html

volatile是Java虛擬機(jī)提供的輕量級(jí)的同步機(jī)制(“乞丐版”的synchronized)

  • 保證可見性

  • 不保證原子性

  • 禁止指令重排

  • 可見性

    指當(dāng)多個(gè)線程訪問同一個(gè)變量時(shí),如果其中一個(gè)線程修改了這個(gè)變量的值,其他線程能夠立即看得到修改的值

    驗(yàn)證可見性demo:

    import java.util.concurrent.TimeUnit;class MyData {volatile int number = 0;public void addTo60() {number = 60;} } public class VolatileDemo {public static void main() {MyData myData = new MyData();new Thread(() -> {System.out.println(Thread.currentThread().getName() + "\t come in");try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}myData.addTo60();System.out.println(Thread.currentThread().getName() + "\t updated number: " + myData.number);}, "AAA").start();while (myData.number == 0) {}System.out.println(Thread.currentThread().getName() + "\t mission is over");} }

    結(jié)果:

    AAA come in main mission is over AAA updated number: 60

    不保證原子性

    原子性:程序中的所有操作是不可中斷的,要么全部執(zhí)行成功要么全部執(zhí)行失敗

    不保證原子性正是volatile輕量級(jí)的體現(xiàn),多個(gè)線程對(duì)volatile修飾的變量進(jìn)行操作時(shí),會(huì)出現(xiàn)容易出現(xiàn)寫覆蓋的情況(i++)

    驗(yàn)證不保證原子性demo:

    import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger;class MyData {volatile int number = 0;public void addPlusPlus() {number++;} } public class VolatileDemo {public static void main(String[] args) {MyData myData = new MyData();for (int i = 0; i < 20; i++) {new Thread(() -> {for (int j = 0; j < 1000; j++) {myData.addPlusPlus();}}, String.valueOf(i)).start();}while (Thread.activeCount() > 2) {Thread.yield();}System.out.println(Thread.currentThread().getName() + "\t finally number value: " + myData.number);} }

    結(jié)果:

    main finally number value: 19109

    解決不保證原子性問題:Atomic

    import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger;class MyData {volatile int number = 0;public void addPlusPlus() {number++;}AtomicInteger atomicInteger = new AtomicInteger();public void addAtmic() {atomicInteger.getAndIncrement();} } public class VolatileDemo {public static void main(String[] args) {MyData myData = new MyData();for (int i = 0; i < 20; i++) {new Thread(() -> {for (int j = 0; j < 1000; j++) {myData.addAtmic();}}, String.valueOf(i)).start();}while (Thread.activeCount() > 2) {Thread.yield();}System.out.println(Thread.currentThread().getName() + "\t finally number value: " + myData.number);System.out.println(Thread.currentThread().getName() + "\t AtomicInteger type,finally number value: "+ myData.atomicInteger);} }

    結(jié)果:

    main finally number value: 19746 main AtomicInteger type,finally number value: 20000

    禁止指令重排

    指令重排:為了提高程序運(yùn)行效率,編譯器可能會(huì)對(duì)輸入指令進(jìn)行重新排序,即程序中各個(gè)語句的執(zhí)行先后順序同代碼中的順序不一定一致。(但是它會(huì)保證單線程程序最終執(zhí)行結(jié)果和代碼順序執(zhí)行的結(jié)果是一致的,它忽略了數(shù)據(jù)的依賴性

    源代碼 -> 編譯器優(yōu)化重排 -> 指令并行重排 -> 內(nèi)存系統(tǒng)重排 -> 最終執(zhí)行指令

    volatile能夠?qū)崿F(xiàn)禁止指令重排的底層原理:

    • 內(nèi)存屏障(Memory Barrier):它是一個(gè)CPU指令。由于編譯器和CPU都能夠執(zhí)行指令重排,如果在指令間插入一條Memory Barrier則會(huì)告訴編譯器和CPU,任何指令都不能和該條Memory Barrier指令進(jìn)行重排序,即通過插入內(nèi)存屏障指令能夠禁止在內(nèi)存屏障前后的指令執(zhí)行重排序 優(yōu)化

    • 內(nèi)存屏障的另外一個(gè)作用是強(qiáng)制刷新各種CPU的緩存數(shù)據(jù),因此任何CPU上的線程都能夠讀取到這些數(shù)據(jù)的最新版本。以上兩點(diǎn)正好對(duì)應(yīng)了volatile關(guān)鍵字的禁止指令重排序和內(nèi)存可見性的特點(diǎn)

    • 對(duì)volatile變量進(jìn)行寫操作時(shí),會(huì)在寫操作之后加入一條store屏障指令,將工作內(nèi)存中的共享變量copy刷新回主內(nèi)存中;對(duì)volatile變量進(jìn)行讀操作時(shí),會(huì)在讀操作之前加入一條load的屏障指令,從主內(nèi)存中讀取共享變量

    應(yīng)用場(chǎng)景:

    • 高并發(fā)環(huán)境下DCL單例模式使用volatile

    public class SingletonDemo {private static volatile SingletonDemo instance = null;private SingletonDemo() {System.out.println(Thread.currentThread().getName() + "我是構(gòu)造方法SingletonDemo()");}public static SingletonDemo getInstance() {if (instance == null) {synchronized (SingletonDemo.class) {if (instance == null) {instance = new SingletonDemo();}}}return instance;}public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(() -> {SingletonDemo.getInstance();}, String.valueOf(i)).start();}}}
    • JUC包下AtomicXxx類:原子類AtomicXxx中都有一個(gè)成員變量value,該value變量被聲明為volatile,保證 AtomicXxx類的內(nèi)存可見性,而原子性由CAS算法&Unsafe類保證,結(jié)合這兩點(diǎn)才能讓AtomicXxx類很好地替代synchronized關(guān)鍵字。

    public class AtomicInteger extends Number implements java.io.Serializable {// ...private volatile int value;// ...}

    總結(jié)

    以上是生活随笔為你收集整理的一文读懂 volatile 关键字的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。