91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java高并發系列 - 第7天:volatile與Java內存模型

發布時間:2020-10-03 13:48:55 來源:網絡 閱讀:189 作者:路人甲Java 欄目:編程語言
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;
    }
}

運行上面代碼,會發現程序無法終止。

線程t1的run()方法中有個循環,通過flag來控制循環是否結束,主線程中休眠了1秒,將flag置為false,按說此時線程t1會檢測到flag為false,打印“線程t1停止了”,為何和我們期望的結果不一樣呢?運行上面的代碼我們可以判斷,t1中看到的flag一直為ture,主線程將flag置為false之后,t1線程中沒有看到,所以一直死循環。

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

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

java高并發系列 - 第7天:volatile與Java內存模型

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

  1. 首先,線程A把本地內存A中更新過的共享變量刷新到主內存中去
  2. 然后,線程B到主內存中去讀取線程A之前已更新過的共享變量

下面通過示意圖來說明這兩個步驟:

java高并發系列 - 第7天:volatile與Java內存模型

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

對JMM了解之后,我們再看看文章開頭的問題,線程t1中為何看不到被主線程修改為false的flag的值,有兩種可能:

  1. 主線程修改了flag之后,未將其刷新到主內存,所以t1看不到
  2. 主線程將flag刷新到了主內存,但是t1一直讀取的是自己工作內存中flag的值,沒有去主內存中獲取flag最新的值

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

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

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

  1. 線程中讀取的時候,每次讀取都會去主內存中讀取共享變量最新的值,然后將其復制到工作內存
  2. 線程中修改了工作內存中變量的副本,修改之后會立即刷新到主內存

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

public volatile static boolean flag = true;

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

線程t1 in
線程t1停止了

這下程序可以正常停止了。

volatile解決了共享變量在多線程中可見性的問題,可見性是指一個線程對共享變量的修改,對于另一個線程來說是否是可以看到的。

java高并發系列連載中,總計估計會有四五十篇文章,可以關注公眾號:javacode2018,獲取最新文章。

java高并發系列 - 第7天:volatile與Java內存模型

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

乐昌市| 句容市| 灌云县| 昭觉县| 和政县| 法库县| 河北区| 句容市| 怀化市| 长寿区| 栾川县| 儋州市| 鸡东县| 侯马市| 绵阳市| 茌平县| 九台市| 前郭尔| 梁平县| 凤山市| 田阳县| 芦溪县| 开阳县| 吉林省| 小金县| 福海县| 二连浩特市| 平昌县| 宁国市| 东至县| 孟州市| 城口县| 菏泽市| 辰溪县| 革吉县| 子洲县| 镇安县| 永顺县| 丹江口市| 岳池县| 大同市|