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

Volatile關(guān)鍵字的使用案例

 更新時間:2023年05月24日 09:50:45   作者:FighterLiu  
這篇文章主要介紹了Volatile關(guān)鍵字的作用,Volatile關(guān)鍵字的作用主要有兩個,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下

Volatile關(guān)鍵字的作用主要有如下兩個:
1.線程的可見性:當一個線程修改一個共享變量時,另外一個線程能讀到這個修改的值。
2. 順序一致性:禁止指令重排序。

一、線程可見性

我們先通過一個例子來看看線程的可見性:

public class VolatileTest {
    boolean flag = true;
    public void updateFlag() {
        this.flag = false;
        System.out.println("修改flag值為:" + this.flag);
    }
    public static void main(String[] args) {
        VolatileTest test = new VolatileTest();
        new Thread(() -> {
            while (test.flag) {
            }
            System.out.println(Thread.currentThread().getName() + "結(jié)束");
        }, "Thread1").start();
        new Thread(() -> {
            try {
                Thread.sleep(2000);
                test.updateFlag();
            } catch (InterruptedException e) {
            }
        }, "Thread2").start();
    }
}

打印結(jié)果如下,我們可以看到雖然線程Thread2已經(jīng)把flag 修改為false了,但是線程Thread1沒有讀取到flag修改后的值,線程一直在運行

修改flag值為:false

我們把flag 變量加上volatile:

volatile  boolean flag = true;

重新運行程序,打印結(jié)果如下。Thread1結(jié)束,說明Thread1讀取到了flage修改后的值

修改flag值為:false

Thread1結(jié)束

說到可見性,我們需要先了解一下Java內(nèi)存模型,Java內(nèi)存模型如下所示:

線程之間的共享變量存儲在主內(nèi)存中(Main Memory)中,每個線程都一個都有一個私有的本地內(nèi)存(Local Memory),本地內(nèi)存中存儲了該線程以讀/寫共享變量的副本。

所以當一個線程把主內(nèi)存中的共享變量讀取到自己的本地內(nèi)存中,然后做了更新。在還沒有把共享變量刷新的主內(nèi)存的時候,另外一個線程是看不到的。

如何把修改后的值刷新到主內(nèi)存中的?
現(xiàn)代的處理器使用寫緩沖區(qū)臨時保存向內(nèi)存寫入的數(shù)據(jù)。寫緩沖區(qū)可以保證指令流水線持續(xù)運行,它可以避免由于處理器停頓下來等向內(nèi)存寫入數(shù)據(jù)而產(chǎn)生的延遲。同時,通過以批處理的方式刷新寫緩沖區(qū),以及合并寫緩沖區(qū)中對同一內(nèi)存地址的多次寫,較少對內(nèi)存總線的占用。但是什么時候?qū)懭氲絻?nèi)存是不知道的。

所以就引入了volatile,volatile是如何保證可見性的呢?
在X86處理器下通過工具獲取JIT編譯器生成的匯編指令來查看對volatile進行寫操作時,會多出lock addl。Lock前綴的指令在多核處理器下會引發(fā)兩件事情:

  • 將當前處理器緩存行的數(shù)據(jù)寫回到系統(tǒng)內(nèi)存。
  • 這個寫回內(nèi)存的操作會使其他cpu里緩存了該內(nèi)存地址的數(shù)據(jù)無效。

如果聲明了volatile的變量進行寫操作,JVM就會向處理器發(fā)送一條Lock前綴的指令,將這個變量所在緩存行的數(shù)據(jù)寫回到系統(tǒng)內(nèi)存。但是,就算寫回到內(nèi)存,如果其他處理器緩存的還是舊的,在執(zhí)行操作就會有問題。所以,在多處理器下,為了保證各個處理器的緩存是一致的,就會實現(xiàn)緩存一致性協(xié)議,每個處理器通過嗅探在總線傳播的數(shù)據(jù)來檢查自己緩存的值是不是過期了,當處理器發(fā)現(xiàn)自己緩存行對應的內(nèi)存地址被修改,就會將當前處理器的緩存行設置成無效狀態(tài),當處理器對這個數(shù)據(jù)進行修改操作的時候,會重新從系統(tǒng)內(nèi)存中把數(shù)據(jù)讀到處理器緩存里。

二、順序一致性

在執(zhí)行程序時,為了提高性能,編譯器和處理器常常會對指令做重排序。重排序分為如下三種:

1屬于編譯器重排序,2和3屬于處理器重排序。這些重排序可能會導致多線程程序出現(xiàn)內(nèi)存可見性問題。
當變量聲明為volatile時,Java編譯器在生成指令序列時,會插入內(nèi)存屏障指令。通過內(nèi)存屏障指令來禁止重排序。
JMM內(nèi)存屏障插入策略如下:
在每個volatile寫操作的前面插入一個StoreStore屏障,后面插入一個StoreLoad屏障。
在每個volatile讀操作后面插入一個LoadLoad,LoadStore屏障。

Volatile寫插入內(nèi)存屏障后生成指令序列示意圖:

Volatile讀插入內(nèi)存屏障后生成指令序列示意圖:

通過上面這些我們可以得出如下結(jié)論:編譯器不會對volatile讀與volatile讀后面的任意內(nèi)存操作重排序;編譯器不會對volatile寫與volatile寫前面的任意內(nèi)存操作重排序。

防止重排序使用案例:

public class SafeDoubleCheckedLocking {
    private volatile static Instance instane;
    public  static Instance getInstane(){
        if(instane==null){
            synchronized (SafeDoubleCheckedLocking.class){
                if(instane==null){
                    instane=new Instance();
                }
            }
        }
        return instane;
    }
}

創(chuàng)建一個對象主要分為如下三步:

  • 分配對象的內(nèi)存空間。
  • 初始化對象。
  • 設置instance指向內(nèi)存空間。

如果instane 不加volatile,上面的2,3可能會發(fā)生重排序。假設A,B兩個線程同時獲取,A線程獲取到了鎖,發(fā)生了指令重排序,先設置了instance指向內(nèi)存空間。這個時候B線程也來獲取,instance不為空,這樣B拿到了沒有初始化完成的單例對象(如下圖)

二、Volatile與Synchronized比較

  • Volatile是輕量級的synchronized,因為它不會引起上下文的切換和調(diào)度,所以Volatile性能更好。
  • Volatile只能修飾變量,synchronized可以修飾方法,靜態(tài)方法,代碼塊。
  • Volatile對任意單個變量的讀/寫具有原子性,但是類似于i++這種復合操作不具有原子性。而鎖的互斥執(zhí)行的特性可以確保對整個臨界區(qū)代碼執(zhí)行具有原子性。
  • 多線程訪問volatile不會發(fā)生阻塞,而synchronized會發(fā)生阻塞。
  • volatile是變量在多線程之間的可見性,synchronize是多線程之間訪問資源的同步性。

到此這篇關(guān)于Volatile關(guān)鍵字的作用的文章就介紹到這了,更多相關(guān)Volatile關(guān)鍵字的作用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文了解Seata的實現(xiàn)原理

    一文了解Seata的實現(xiàn)原理

    隨著業(yè)務發(fā)展,單體系統(tǒng)逐漸無法滿足業(yè)務的需求,分布式架構(gòu)逐漸成為大型互聯(lián)網(wǎng)平臺首選。伴隨而來的問題是,本地事務方案已經(jīng)無法滿足,分布式事務相關(guān)規(guī)范和框架應運而生。本文主要介紹Seata的實現(xiàn)原理
    2021-06-06
  • Spring事務失效場景及解決過程

    Spring事務失效場景及解決過程

    這篇文章主要介紹了Spring事務失效場景及解決過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-07-07
  • SpringCloud maven-assembly-plugin 多級目錄打包的實現(xiàn)

    SpringCloud maven-assembly-plugin 多級目錄打包的實現(xiàn)

    本文主要介紹了SpringCloud maven-assembly-plugin 多級目錄打包的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • idea設置快捷鍵風格方式

    idea設置快捷鍵風格方式

    在IntelliJIDEA中設置快捷鍵風格,打開IDEA,進入設置頁面,選擇Keymap,從Keymaps下拉列表中選擇或復制想要的快捷鍵風格,點擊Apply和OK即可使用,如果需要修改某個功能的快捷鍵,選擇功能項,右鍵選擇相應的設置項進行設置
    2025-12-12
  • Java不可變類機制淺析

    Java不可變類機制淺析

    所謂的不可變類是指這個類的實例一旦創(chuàng)建完成后,就不能改變其成員變量值。如JDK內(nèi)部自帶的很多不可變類:Interger、Long和String等。接下來通過本文給大家介紹Java不可變類機制,需要的朋友參考下
    2017-02-02
  • Java的List集合框架之Vector詳細解析

    Java的List集合框架之Vector詳細解析

    這篇文章主要介紹了Java的List集合框架之Vector詳細解析,List接口繼承Collection,Collection繼承于Iterable,List接口實現(xiàn)類分為Vector、ArrayList、LinkedList,Vector底層是一個Object數(shù)組,需要的朋友可以參考下
    2023-11-11
  • 圖解Java經(jīng)典算法希爾排序的原理與實現(xiàn)

    圖解Java經(jīng)典算法希爾排序的原理與實現(xiàn)

    希爾排序是希爾(Donald Shell)于1959年提出的一種排序算法。希爾排序也是一種插入排序,它是簡單插入排序經(jīng)過改進之后的一個更高效的版本,也稱為縮小增量排序,同時該算法是沖破O(n2)的第一批算法之一。本文會以圖解的方式詳細介紹希爾排序的基本思想及其代碼實現(xiàn)
    2022-09-09
  • ibatis結(jié)合oracle批量插入三種方法的測評

    ibatis結(jié)合oracle批量插入三種方法的測評

    今天小編就為大家分享一篇關(guān)于ibatis結(jié)合oracle批量插入三種方法的測評,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Java?C++題解eetcode940不同的子序列?II

    Java?C++題解eetcode940不同的子序列?II

    這篇文章主要為大家介紹了Java?C++題解eetcode940不同的子序列?II實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • 基于Comparator對象集合實現(xiàn)多個條件按照優(yōu)先級的比較

    基于Comparator對象集合實現(xiàn)多個條件按照優(yōu)先級的比較

    這篇文章主要介紹了基于Comparator對象集合實現(xiàn)多個條件按照優(yōu)先級的比較,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07

最新評論

嵩明县| 图们市| 和静县| 靖西县| 通化县| 阜阳市| 莱州市| 临颍县| 拉孜县| 华宁县| 凤山县| 咸宁市| 长宁县| 醴陵市| 玉门市| 平远县| 天峻县| 囊谦县| 新田县| 开鲁县| 屏东县| 靖州| 满城县| 开原市| 买车| 渭南市| 安庆市| 康乐县| 于田县| 河池市| 嘉义县| 万年县| 哈密市| 青冈县| 南木林县| 丰城市| 泾源县| 长子县| 紫阳县| 澜沧| 望江县|