" />

欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java 中的volatile關(guān)鍵字

 更新時(shí)間:2021年12月12日 12:03:49   作者:bkpp976  
這篇文章主要介紹了java 中的volatile關(guān)鍵字,volatile在多處理器開(kāi)發(fā)中保證共享變量的“可見(jiàn)性”??梢?jiàn)性的意思是當(dāng)一個(gè)線程修改一個(gè)共享變量時(shí),另一個(gè)一個(gè)線程立馬可以讀到這個(gè)修改的值。下面我們來(lái)看看文章的具體介紹內(nèi)容吧

1.volatile實(shí)現(xiàn)可見(jiàn)性的原理是什么?

volatile變量修飾的共享變量進(jìn)行寫操作的時(shí)候匯編代碼會(huì)多出一個(gè)Lock前綴指令。

在該指令下,多核處理器會(huì)引發(fā)兩件事:

  • 將當(dāng)前處理器緩存行的數(shù)據(jù)寫回系統(tǒng)內(nèi)存
  • 這個(gè)寫回內(nèi)存的操作會(huì)使在其他CPU里緩存了該內(nèi)存地址的數(shù)據(jù)無(wú)效

這里需要簡(jiǎn)單了解CPU緩存一致性問(wèn)題:多核處理器環(huán)境下,每個(gè)CPU都有自己的緩存行,緩存了內(nèi)存中的數(shù)據(jù),要維護(hù)多個(gè)CPU中緩存的數(shù)據(jù)一致性,就需要解決兩個(gè)問(wèn)題:

  • 一是寫傳播(某個(gè)CPU里的cache數(shù)據(jù)更新時(shí),需要傳播到其他CPU的cache中);
  • 二是事務(wù)的串行化執(zhí)行(在某個(gè)CPU里對(duì)數(shù)據(jù)的修改,在其他CPU中看起來(lái)順序是一樣的,也就是要引入近似[鎖]的概念,保證同一時(shí)刻只有一個(gè)CPU可以對(duì)數(shù)據(jù)做修改);

寫傳播是通過(guò)[總線嗅探]完成的:通過(guò)總線把修改數(shù)據(jù)的事件廣播通知給其他所有的核心,每個(gè)CPU核心都會(huì)監(jiān)聽(tīng)總線上的廣播事件,并檢查是否有相同的數(shù)據(jù)在自己的Cache里面;而事務(wù)的串行化則通過(guò)[MESI協(xié)議]來(lái)完成。

MESI(Modified(已修改)、Exclusive(獨(dú)占)、Shared(共享)、Ivalidated(已失效))協(xié)議中,如果要修改一個(gè)共享數(shù)據(jù),不能直接修改,要先向其他CPU廣播一個(gè)請(qǐng)求,把其他CPU cache中對(duì)應(yīng)的數(shù)據(jù)狀態(tài)改為Invalidated;以后其他CPU在讀取標(biāo)記為Invalidated的數(shù)據(jù)時(shí),需要強(qiáng)制從內(nèi)存中讀取數(shù)據(jù)。

2.演示volatile的可見(jiàn)性

public class VolatileDemo {
    static  int flag = 1;  // 定義一個(gè)共享變量
    public static void main(String[] args) {
        // 兩個(gè)線程,一個(gè)線程負(fù)責(zé)讀取flag的值,另一個(gè)線程負(fù)責(zé)修改flag的值
        new Thread(){
            int localflag = flag;
            @Override
            public void run() {
                while(true){
                    //flag被修改后就跟localflag不一樣了
                    if(localflag!=flag){
                        System.out.println("讀到了flag修改后的值:"+ flag);
                        //把讀到的值賦值給本地變量
                        localflag = flag;
                    }
                }
            }
        }.start();

        new Thread(){
            int localflag = flag;
            @Override
            public void run() {
                while (true){
                    //一直對(duì)flag的值進(jìn)行修改
                    System.out.println("對(duì)flag的值進(jìn)行修改:"+ ++localflag);
                    flag = localflag;
                    //休眠一秒更好地觀察結(jié)果
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();


    }
}

可以看到另一個(gè)線程并不能及時(shí)讀取到被修改的值。

共享變量用volatile修飾后:

public class VolatileDemo {
    static  volatile int flag = 1;
    public static void main(String[] args) {
        // 兩個(gè)線程,一個(gè)線程負(fù)責(zé)讀取flag的值,另一個(gè)線程負(fù)責(zé)修改flag的值
        new Thread(){
            int localflag = flag;
            @Override
            public void run() {
                while(true){
                    //flag被修改后就跟localflag不一樣了
                    if(localflag!=flag){
                        System.out.println("讀到了flag修改后的值:"+ flag);
                        //把讀到的值賦值給本地變量
                        localflag = flag;
                    }
                }
            }
        }.start();

        new Thread(){
            int localflag = flag;
            @Override
            public void run() {
                while (true){
                    //一直對(duì)flag的值進(jìn)行修改
                    System.out.println("對(duì)flag的值進(jìn)行修改:"+ ++localflag);
                    flag = localflag;
                    //休眠一秒更好地觀察結(jié)果
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();


    }
}

可以看到用volatile修飾后,每次另一個(gè)線程總能讀取到修改后的值。

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

相關(guān)文章

  • MyBatis注解開(kāi)發(fā)-@Insert和@InsertProvider的使用

    MyBatis注解開(kāi)發(fā)-@Insert和@InsertProvider的使用

    這篇文章主要介紹了MyBatis注解開(kāi)發(fā)-@Insert和@InsertProvider的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2022-07-07
  • 關(guān)于@PostConstruct、afterPropertiesSet和init-method的執(zhí)行順序

    關(guān)于@PostConstruct、afterPropertiesSet和init-method的執(zhí)行順序

    這篇文章主要介紹了關(guān)于@PostConstruct、afterPropertiesSet和init-method的執(zhí)行順序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 兩個(gè)jar包下相同包名類名引入沖突的解決方法

    兩個(gè)jar包下相同包名類名引入沖突的解決方法

    本文主要介紹了兩個(gè)jar包下相同包名類名引入沖突的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 圖解Java排序算法之堆排序

    圖解Java排序算法之堆排序

    這篇文章主要為大家詳細(xì)介紹了Java經(jīng)典排序算法之堆排序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 使用java實(shí)現(xiàn)猜拳小游戲

    使用java實(shí)現(xiàn)猜拳小游戲

    這篇文章主要為大家詳細(xì)介紹了使用java實(shí)現(xiàn)猜拳小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Java中的接口知識(shí)匯總

    Java中的接口知識(shí)匯總

    本文給大家匯總介紹了在java中的接口知識(shí),包括為什么要使用接口、什么是接口、抽象類和接口的區(qū)別、如何定義接口以及定義接口注意點(diǎn),希望大家能夠喜歡
    2016-04-04
  • Java中keytool的使用

    Java中keytool的使用

    Keytool 是一個(gè)JAVA環(huán)境下的安全鑰匙與證書的管理工具,Keytool將密鑰(key)和證書(certificates)存在一個(gè)稱為keystore 的文件(受密碼保護(hù))中,本文重點(diǎn)給大家介紹keytool的使用,感興趣的朋友一起看看吧
    2022-02-02
  • java框架基礎(chǔ)之SPI機(jī)制實(shí)現(xiàn)及源碼解析

    java框架基礎(chǔ)之SPI機(jī)制實(shí)現(xiàn)及源碼解析

    這篇文章主要為大家介紹了java框架基礎(chǔ)之SPI機(jī)制實(shí)現(xiàn)及源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 詳解Redis 緩存 + Spring 的集成示例

    詳解Redis 緩存 + Spring 的集成示例

    本篇文章主要介紹了Redis 緩存 + Spring 的集成示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-04-04
  • 詳解如何查看Elasticsearch的Debug日志

    詳解如何查看Elasticsearch的Debug日志

    這篇文章主要為大家介紹了詳解如何查看Elasticsearch的Debug日志,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11

最新評(píng)論