深入分析volatile是如何實現可見性和有序性的

2020-11-30 Java章魚小弟

並發編程中常常繞不開原子性、可見性與有序性的討論。先來看看什麼是原子性?

什麼是原子性

原子(atomic)本意是不能被進一步分割的最小粒子,而原子操作意為不可被中斷的一個或者一系列操作。

volatile是不能保證原子性,但是在特定場景就是在32位處理器裡,對double和long型的變量的讀寫操作加了volatile修飾可以保證原子性。因為double和long都是64位,當JVM在32位處理器上運行時,可能會把64位的double/long型變量拆分為兩個32位的寫操作來執行,其他處理器可能讀到一個「寫了一半」的無效值,加了volatile就可以保證原子性。

內存屏障

可見性和有序性是基於各種內存屏障(禁止指令重排序)來實現的,先來看下有哪些內存屏障類型,以及可以解決那些因重排序引起的有序性問題。對有序性不太理解的同學可以先看下前這篇文章面試官:你知道happens-before規則嗎

本文的重點來了,對於volatile修復的變量,在它的讀/寫操作前後都會加上不同的內存屏障。

在每個volatile寫操作的前面插入一個StoreStore屏障,後面插入一個StoreLoad屏障,保證volatile寫與之前的寫操作指令不會重排序,寫完數據之後立即執行flush處理器緩存操作將所有寫操作刷到內存,對所有處理器可見。在每個volatilie讀操作的前面插入一LoadLoad屏障,保證在該變量讀操作時,如果其他處理修改過,必須從其他處理器高速緩存(或者主內存)加載到自己本地高速緩存,保證讀取到的值是最新的。然後在該變量讀操作後面插入一個LoadStore屏障,禁止volatile讀操作與後面任意讀寫操作重排序。

volatile底層實現可見性與有序性原理

1、關於實現有序性,主要通過對volatile修飾的變量的讀寫操作前後加上各種特定的內存屏障來禁止指令重排序來保障有序性的。

2、關於實現可見性,主要是通過 Lock前綴指令 + MESI緩存一致性協議來實現的。對volatiile修飾的變量執行寫操作時,JVM會發送一個Lock前綴指令給CPU,CPU在執行完寫操作後,會立即將新值刷新到內存,同時因為MESI緩存一致性協議,其他各個CPU都會對總線嗅探,看自己本地緩存中的數據是否被別人修改,如果發現修改了,會把自己本地緩存的數據過期掉。然後這個CPU裡的線程在讀取改變量時,就會從主內存裡加載最新的值了,這樣就保證了可見性。各位看官還可以參考這篇文章CPU是如何通過緩存一致性MESI協議來解決可見性的

相關焦點

  • 並發之原子性、有序性、可見性
    多線程編程雖然可以最大限度地利用CPU,但也突顯了三個問題:原子性問題,可見性問題,有序性問題。原子性atomic原子性指的是一個或者多個操作在CPU執行過程中不被中斷的特性。即要不全部執行完成,要不不執行。
  • Java中volatile關鍵字概覽
    Java內存模型(Java Memory Model)描述了Java程序中各種變量(線程共享變量)的訪問規則,以及在JVM中將變量存儲到內存和從內存中讀取變量這樣的底層細節。JMM有以下規定:所有的共享變量都存儲於主內存。這裡所說的變量指的是實例變量和類變量。不包含局部變量,因為局部變量 是線程私有的,因此不存在競爭問題。
  • Java研發技術——Volatile原理詳解
    禁止指令重排可見性volatile讀的內存語義當讀一個volatile變量時,JMM會把該線程對應的本地內存置為無效。線程接下來將從主內存中讀取共享變量(注意不僅僅是一個volatile變量,是所有共享變量)volatile寫的內存語義當寫一個volatile變量時,JMM會把該線程對應的本地內存中的共享變量值刷新到主內存(注意不僅僅是一個volatile變量,是所有共享變量)可見性
  • 為什麼要加volatile?
    實現我們將創建一個 SingleObject 類。SingleObject 類有它的私有構造函數和本身的一個靜態實例。SingleObject 類提供了一個靜態方法,供外界獲取它的靜態實例。SingletonPatternDemo,我們的演示類使用 SingleObject 類來獲取 SingleObject 對象。
  • 高質量的論文摘要,是如何提升論文可見性的?
    在我們的論文寫作中,如何有效地利用論文摘要提升文章的可見性?我們將從以下幾個方面詳細介紹。 01 用搜尋引擎優化摘要 搜尋引擎的優化是提升論文可見性的捷徑。
  • 圖解golang裡面的讀寫鎖實現與核心原理分析了解程式語言背後設計
    在說golang之前介紹一種JAVA裡面的實現,在JAVA中ReentrantReadWriteLock實現採用一個state的高低位來進行讀寫鎖的計數,其中高16位存儲讀的計數,低16位存儲寫的計數,並配合一個AQS來實現排隊等待機制,同時AQS中的每個waiter都會有一個status,用來標識自己的狀態2. golang的讀寫鎖的實現2.1 成員變量
  • C語言 volatile 關鍵字在編譯優化過程中有何作用
    >define     __IO    volatile              瀏覽代碼,你會發現,很多地方都使用了「__IO」,也就是volatile. 優化可能會導致刪除實現故意時序延遲的代碼。
  • 當我們在思考「可見性」時,我們在思考什麼?
    理解可見性的三維模型對於如此重要的傳播學概念,我們應該去如何理解它?傳播學者對於可見性的討論很多。不過,他們雖然使用同一個詞,但卻表達了不同的意思。在Treem(2020)眼中,可見性不是單向的,而是一種「互動」:一邊是表演,一邊是觀看。
  • C語言之const和volatile"究極"學習
    1、volatile的常用結論(volatile英文本意就是易變的意思)這裡我先給結論,然後再給一個例子,把這個例子的講明白,所有結論就都明白了。volatile可理解為「編譯器警告指示字」volatile告訴編譯器必須每次去內存中取變量值volatile主要修飾可能被多個線程訪問的變量volatile也可以修飾可能被未知因素更改的變量volatile可以修飾一個中斷子程序中會訪問到的非自動變量2、分析原理大家可能平時在博客學習,都會發現講解編譯器優化的
  • 病毒DNA在受限空間中的多區域有序性研究獲進展
    病毒,有著各種各樣的形狀和大小,既有極其微小的二十面體鼻病毒(如普通流感病毒),也有較大尺寸的磚型正痘病毒(如天花)。然而,DNA是以怎樣的形態和方式堆積在病毒內部的,仍舊是一個具有爭議的問題。最近,中國科學院物理研究所/北京凝聚態物理國家研究中心的研究人員在《物理評論快報》上發表了一篇文章,通過理論分析和數值模擬,解答了這一病毒DNA的堆積問題。
  • 進展|病毒DNA在受限空間中的多區域有序性
    病毒,有著各種各樣的形狀和大小,既有極其微小的二十面體鼻病毒(如普通流感病毒),也有較大尺寸的磚型正痘病毒(如天花)。然而,DNA是以怎樣的形態和方式堆積在病毒內部的,仍舊是一個具有爭議的問題。最近,中國科學院物理研究所/北京凝聚態物理國家研究中心的研究人員在《物理評論快報》上發表了一篇文章,通過理論分析和數值模擬,解答了這一病毒DNA的堆積問題。文章的作者把DNA在病毒內的堆積問題簡化為一根被限制在球殼內的彈性細絲。
  • 深入淺出的機制,深度把握JVM高級特性和實踐
    介紹了類加載過程的「加載」「驗證」「準備」「解析」和「初始化」五個階段中虛擬機分別進行了 哪些動作,還介紹了類加載器的工作原理及其對虛擬機的意義。分析了虛擬機在執行代碼時,如何找到正確的方法、如何執行方法內的字節碼,以及執行代碼時涉及的內存結構。通過幾個類加載及執行子系統的案例,介紹了使用類加載器和處理字節碼的一些值得欣賞 和借鑑的思路,並通過一個實戰練習加深讀者對前面理論知識的理解。
  • 掌握了數據分析,你還怕搞不定供應鏈管理?
    全球形勢已促使IT領導人加快採用數據分析技術,以確保供應鏈的有效性和完整性。一些企業組織發現,數據分析和相關技術(比如人工智慧和機器學習)是確保供應鏈卓越管理的關鍵,無論是為了確保供應鏈的完整性,還是應對快速增長和複雜形勢。下面介紹了幾家企業組織如何運用數據分析技術來獲得成效。
  • 深入剖析UML類圖依賴關係
    深入剖析UML類圖依賴關係 UML類中有泛化,依賴,關係,和聚集等關係,你是否都熟悉,這裡就向大家介紹一下UML類圖依賴關係,希望通過本文的學習你對UML類圖有更深入的認識。
  • Java中long和double的非原子性你了解嗎?
    三個特性JMM的三大特性:可見性、有序性、原子性。八個原子操作Java內存模型要求lock、unlock、read、load、use、assign、store、write這8個操作都具有原子性。問題分析Java中有8種基本數據類型,為什麼只有long和double是非原子性的呢?
  • 深入分析java中的多態(從jvm角度分析)
    重寫的參數列表和返回類型均不可修改。我們再舉個例子,就是子承父業,但是兒子有自己想法,對父親得產業進行再投資的過程。二、代碼實現多態1、類內部之間得多態:方法重載從上述代碼我們可以看到,在類的內部可以有相同的方法名,但是有唯一的參數列表。當然返回類型和修飾符也可以不同。
  • GitLab 發布新版本12.3,新增加Web應用防火牆和生產力分析等
    生產力分析(PREMIUM及以上)各地的軟體交付團隊都需要正確的信息和見識,以提高生產力和效率。通常,看不見的瓶頸和障礙會迫使團隊等待和浪費時間,而不是提供新功能。Gitlab 12.3新增加生產力分析功能用來幫助團隊和領導者更好地了解小組和項目的整體生產力和有效性。生產力分析將幫助團隊及其領導者發現最佳實踐,以提高生產力。
  • CPDA數據分析師:揭秘數據完整性和數據質量之間的差異
    3、數據的有效性如何?信息必須符合業務需求所定義的語法和結構。 4、數據是何時獲取的,是否及時?為了使數據真正使組織受益,它必須是最新的。 5、數據條目的一致性如何?數據必須以標準方式表示和存儲。