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

java高并發(fā)的volatile與Java內(nèi)存模型詳解

 更新時(shí)間:2021年10月27日 10:07:58   作者:路人甲Java  
這篇文章主要介紹了java高并發(fā)的volatile與Java內(nèi)存模型,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
public class Demo09 {	
    public static boolean flag = true;	
    public static class T1 extends Thread {	
        public T1(String name) {	
            super(name);	
        }	
        @Override	
        public void run() {	
            System.out.println("線程" + this.getName() + " in");	
            while (flag) {	
                ;	
            }	
            System.out.println("線程" + this.getName() + "停止了");	
        }	
    }	
    public static void main(String[] args) throws InterruptedException {	
        new T1("t1").start();	
        //休眠1秒	
        Thread.sleep(1000);	
        //將flag置為false	
        flag = false;	
    }	
}

運(yùn)行上面代碼,會(huì)發(fā)現(xiàn)程序無(wú)法終止。

線程t1的run()方法中有個(gè)循環(huán),通過flag來(lái)控制循環(huán)是否結(jié)束,主線程中休眠了1秒,將flag置為false,按說(shuō)此時(shí)線程t1會(huì)檢測(cè)到flag為false,打印“線程t1停止了”,為何和我們期望的結(jié)果不一樣呢?運(yùn)行上面的代碼我們可以判斷,t1中看到的flag一直為true,主線程將flag置為false之后,t1線程中并沒有看到,所以一直死循環(huán)。

那么t1中為什么看不到被主線程修改之后的flag?

要解釋這個(gè),我們需要先了解一下java內(nèi)存模型(JMM),Java線程之間的通信由Java內(nèi)存模型(本文簡(jiǎn)稱為JMM)控制,JMM決定一個(gè)線程對(duì)共享變量的寫入何時(shí)對(duì)另一個(gè)線程可見。從抽象的角度來(lái)看,JMM定義了線程和主內(nèi)存之間的抽象關(guān)系:線程之間的共享變量存儲(chǔ)在主內(nèi)存(main memory)中,每個(gè)線程都有一個(gè)私有的本地內(nèi)存(local memory),本地內(nèi)存中存儲(chǔ)了該線程以讀/寫共享變量的副本。本地內(nèi)存是JMM的一個(gè)抽象概念,并不真實(shí)存在。它涵蓋了緩存,寫緩沖區(qū),寄存器以及其他的硬件和編譯器優(yōu)化。Java內(nèi)存模型的抽象示意圖如下:

640?wx_fmt=png

從上圖中可以看出,線程A需要和線程B通信,必須要經(jīng)歷下面2個(gè)步驟:

1.首先,線程A把本地內(nèi)存A中更新過的共享變量刷新到主內(nèi)存中去

2.然后,線程B到主內(nèi)存中去讀取線程A之前已更新過的共享變量

下面通過示意圖來(lái)說(shuō)明這兩個(gè)步驟:

640?wx_fmt=png

如上圖所示,本地內(nèi)存A和B有主內(nèi)存中共享變量x的副本。假設(shè)初始時(shí),這三個(gè)內(nèi)存中的x值都為0。線程A在執(zhí)行時(shí),把更新后的x值(假設(shè)值為1)臨時(shí)存放在自己的本地內(nèi)存A中。當(dāng)線程A和線程B需要通信時(shí),線程A首先會(huì)把自己本地內(nèi)存中修改后的x值刷新到主內(nèi)存中,此時(shí)主內(nèi)存中的x值變?yōu)榱?。隨后,線程B到主內(nèi)存中去讀取線程A更新后的x值,此時(shí)線程B的本地內(nèi)存的x值也變?yōu)榱?。從整體來(lái)看,這兩個(gè)步驟實(shí)質(zhì)上是線程A在向線程B發(fā)送消息,而且這個(gè)通信過程必須要經(jīng)過主內(nèi)存。JMM通過控制主內(nèi)存與每個(gè)線程的本地內(nèi)存之間的交互,來(lái)為java程序員提供內(nèi)存可見性保證。

對(duì)JMM了解之后,我們?cè)倏纯次恼麻_頭的問題,線程t1中為何看不到被主線程修改為false的flag的值,有兩種可能:

1.主線程修改了flag之后,未將其刷新到主內(nèi)存,所以t1看不到

2.主線程將flag刷新到了主內(nèi)存,但是t1一直讀取的是自己工作內(nèi)存中flag的值,沒有去主內(nèi)存中獲取flag最新的值

對(duì)于上面2種情況,有沒有什么辦法可以解決?

是否有這樣的方法:線程中修改了工作內(nèi)存中的副本之后,立即將其刷新到主內(nèi)存;工作內(nèi)存中每次讀取共享變量時(shí),都去主內(nèi)存中重新讀取,然后拷貝到工作內(nèi)存。

java幫我們提供了這樣的方法,使用volatile修飾共享變量,就可以達(dá)到上面的效果,被volatile修改的變量有以下特點(diǎn):

1.線程中讀取的時(shí)候,每次讀取都會(huì)去主內(nèi)存中讀取共享變量最新的值,然后將其復(fù)制到工作內(nèi)存

2.線程中修改了工作內(nèi)存中變量的副本,修改之后會(huì)立即刷新到主內(nèi)存

我們修改一下開頭的示例代碼:

public volatile static boolean flag = true;

使用volatile修飾flag變量,然后運(yùn)行一下程序,輸出:

線程t1 in	
線程t1停止了

這下程序可以正常停止了。volatile解決了共享變量在多線程中可見性的問題,可見性是指一個(gè)線程對(duì)共享變量的修改,對(duì)于另一個(gè)線程來(lái)說(shuō)是否是可以看到的。\

總結(jié)

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • Java設(shè)計(jì)模塊系列之書店管理系統(tǒng)單機(jī)版(一)

    Java設(shè)計(jì)模塊系列之書店管理系統(tǒng)單機(jī)版(一)

    這篇文章主要為大家詳細(xì)介紹了Java單機(jī)版的書店管理系統(tǒng)設(shè)計(jì)模塊和思想第一章,感興趣的小伙伴們可以參考一下
    2016-08-08
  • JavaWeb表單注冊(cè)界面的實(shí)現(xiàn)方法

    JavaWeb表單注冊(cè)界面的實(shí)現(xiàn)方法

    這篇文章主要介紹了JavaWeb表單注冊(cè)界面的實(shí)現(xiàn)方法的相關(guān)資料,希望通過本文大家能掌握這部分內(nèi)容,需要的朋友可以參考下
    2017-09-09
  • SpringBoot整合TKMyBatis實(shí)現(xiàn)單表增刪改查操作

    SpringBoot整合TKMyBatis實(shí)現(xiàn)單表增刪改查操作

    據(jù)說(shuō)tk.mybatis能夠讓我不寫sql代碼就可以所有單表操作問題,作為熱愛偷懶的我,怎么能放過這種機(jī)會(huì)。talk is cheap, show me the code。趕緊搞個(gè)例子爽一把先
    2023-01-01
  • Spring 中使用反射創(chuàng)建 Bean 實(shí)例的幾種方式

    Spring 中使用反射創(chuàng)建 Bean 實(shí)例的幾種方式

    文章介紹了在Spring框架中如何使用反射來(lái)創(chuàng)建Bean實(shí)例,包括使用Class.newInstance()、Constructor.newInstance()、工廠方法以及Spring的BeanUtils工具類,文章還強(qiáng)調(diào)了反射操作的注意事項(xiàng),如異常處理、性能、安全性以及類型安全,感興趣的朋友一起看看吧
    2025-03-03
  • Java并發(fā)中的Fork/Join 框架機(jī)制詳解

    Java并發(fā)中的Fork/Join 框架機(jī)制詳解

    本文主要介紹了 Java 并發(fā)框架中的 Fork/Join 框架的基本原理和其使用的工作竊取算法(work-stealing)、設(shè)計(jì)方式和部分實(shí)現(xiàn)源碼,感興趣的朋友跟隨小編一起看看吧
    2021-07-07
  • Java通過JNI 調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL操作

    Java通過JNI 調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL操作

    這篇文章主要介紹了Java通過JNI 調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧
    2020-11-11
  • Java split函數(shù)拆分后變成null問題解決方案

    Java split函數(shù)拆分后變成null問題解決方案

    這篇文章主要介紹了Java split函數(shù)拆分后變成null問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • MyEclipse安裝JS代碼提示的教程(Spket插件)

    MyEclipse安裝JS代碼提示的教程(Spket插件)

    本篇文章主要介紹了MyEclipse安裝JS代碼提示的教程(Spket插件),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2017-12-12
  • java List集合接口的介紹和使用全面教程

    java List集合接口的介紹和使用全面教程

    這篇文章主要為大家介紹了java List集合接口的介紹和使用全面教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Java中ThreadPoolExecutor拒絕策略踩坑

    Java中ThreadPoolExecutor拒絕策略踩坑

    本文主要介紹了Java中ThreadPoolExecutor拒絕策略踩坑,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06

最新評(píng)論

乌拉特中旗| 石首市| 洛阳市| 永修县| 青阳县| 高清| 揭东县| 云霄县| 衡山县| 垫江县| 阳春市| 桂林市| 鹤峰县| 福鼎市| 松原市| 八宿县| 鸡泽县| 岐山县| 武安市| 抚顺县| 威宁| 中山市| 丹凤县| 米易县| 吉林市| 长宁县| 曲阳县| 毕节市| 泰顺县| 石家庄市| 汤阴县| 东港市| 遂溪县| 开阳县| 三门峡市| 清水河县| 墨竹工卡县| 海南省| 平果县| 马关县| 凭祥市|