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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

volatile关键字到底做了什么?

發布時間:2025/3/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 volatile关键字到底做了什么? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?話不多說,直接貼代碼

class Singleton {private static volatile Singleton instance;private Singleton(){}//雙重判空public static Singleton getInstance() {if ( instance == null ) {synchronized (Singleton.class) {if ( instance == null ) {instance = new Singleton();}}}return instance;} }

?? 這是一個大家耳熟能詳的單例實現,其中有兩個關鍵要點,一是使用雙重檢查鎖定(Double-Checked Locking)來盡量延遲加鎖時間,以盡量降低同步開銷;二就是instance實例上加了volatile關鍵字。那么為什么一定要加volatile關鍵字,volatile又為我們做了什么事情呢?

?? 要了解這個問題,我們先要搞清楚三個概念:java內存模型(JMM)、happen-before原則、指令重排序。

  1.java內存模型(Java Memory Model)

    Java內存模型中規定了所有的變量都存儲在主內存中,每條線程還有自己的工作內存,線程的工作內存中使用到的變量需要到主內存去拷貝,線程對變量的所有操作(讀取、賦值)都必須在工作內存中進行,而不能直接讀寫主內存中的變量。不同線程之間無法直接訪問對方工作內存中的變量,線程間變量值的傳遞均需要在主內存來完成,線程、主內存和工作內存的交互關系如下圖所示:

    

  2.happen-before原則

    Java語言中有一個“先行發生”(happen—before)的規則,它是Java內存模型中定義的兩項操作之間的偏序關系,如果操作A先行發生于操作B,其意思就是說,在發生操作B之前,操作A產生的影響都能被操作B觀察到,“影響”包括修改了內存中共享變量的值、發送了消息、調用了方法等,它與時間上的先后發生基本沒有太大關系。這個原則特別重要,它是判斷數據是否存在競爭、線程是否安全的主要依據。

    下面是Java內存模型中的八條可保證happen—before的規則,它們無需任何同步器協助就已經存在,可以在編碼中直接使用。如果兩個操作之間的關系不在此列,并且無法從下列規則推導出來的話,它們就沒有順序性保障,虛擬機可以對它們進行隨機地重排序。

    

  • 單線程happen-before原則:在同一個線程中,書寫在前面的操作happen-before后面的操作。
  • 鎖的happen-before原則:同一個鎖的unlock操作happen-before此鎖的lock操作。
  • volatile的happen-before原則:對一個volatile變量的寫操作happen-before對此變量的任意操作(當然也包括寫操作了)。
  • happen-before的傳遞性原則:如果A操作 happen-before B操作,B操作happen-before C操作,那么A操作happen-before C操作。
  • 線程啟動的happen-before原則:同一個線程的start方法happen-before此線程的其它方法。
  • 線程中斷的happen-before原則:對線程interrupt方法的調用happen-before被中斷線程的檢測到中斷發送的代碼。
  • 線程終結的happen-before原則:線程中的所有操作都happen-before線程的終止檢測。
  • 對象創建的happen-before原則:一個對象的初始化完成先于他的finalize方法調用。

?

  3.指令重排序

    對主存的一次訪問一般花費硬件的數百次時鐘周期。處理器通過緩存(caching)能夠從數量級上降低內存延遲的成本,這些緩存為了性能重新排列待定內存操作的順序。也就是說,程序的讀寫操作不一定會按照它要求處理器的順序執行。

    JMM通過happens-before法則保證順序執行語義,如果想要讓執行操作B的線程觀察到執行操作A的線程的結果,那么A和B就必須滿足happens-before原則,否則,JVM可以對它們進行任意排序以提高程序性能。

?

? ? 基于以上三個概念,我們可以拆解 instance =?new?Singleton() 這段代碼:

?

// thread-A memory = allocate();  // 1:分配對象的內存空間 ctorInstance(memory); // 2:初始化對象 instance = memory;  // 3:設置instance指向剛分配的內存地址

?

?? 然而,由于happen-before原則并不能保證這段代碼的順序性,這段代碼可能被編譯器優化為:

//thread-B memory = allocate();  // 1:分配對象的內存空間 instance = memory;   // 3:設置instance指向剛分配的內存地址 ctorInstance(memory); // 2:初始化對象

?? 在單線程中不論是以哪種順序執行,都不會對結果有任何影響,然而在多線程下,有可能出現thread-B的執行順序,盡管由于同步鎖的存在,不會出現兩個線程同時進入instance =?new?Singleton()的場景,但是若B線程執行完3之后,2還沒有執行,CPU就切換時間片,執行一個全新的C線程,將導致C線程拿到一個非空的instance,然而這時候該instance還沒有準備好。

?? 而這一切,僅僅需要在instance實例前加上volatile,就可以完美的解決。

?? 那么,volatile在例子中到底做了什么神奇的操作呢?

   其一,對于volatile修飾的instance變量,若對instance的寫操作執行在前,那么該寫操作的結果一定會被立刻刷新到主內存中,之后所有線程對于該instance的所有讀寫操作必然可以觀察到最新的值,也即:volatile保證了變量的內存可見性

?????? 其二,對于volatile修飾的instance變量,將不允許任何與其相關的操作進行指令重排序

 

https://www.cnblogs.com/Jasonchan1994/p/10696930.html

總結

以上是生活随笔為你收集整理的volatile关键字到底做了什么?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。