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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

JMM理论二:相关概念——重排序、内存屏障、数据依赖、as-if-serial、final、Happen-Before

發布時間:2023/12/16 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JMM理论二:相关概念——重排序、内存屏障、数据依赖、as-if-serial、final、Happen-Before 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

參考致謝:
https://blog.csdn.net/zjcjava/article/details/78406330
Java 并發編程 - cuzz’s blog
https://www.jianshu.com/p/8a58d8335270
java內存模型JMM理解整理 - 阿姆斯特朗回旋炮 - 博客園 (cnblogs.com)

1 重排序

1、計算機在執行程序時,為了提高并行度,編譯器和處理器常常會對指令做重排序。

2、指令重排序的條件:
1)在單線程環境下不能改變程序的運行結果。
2)存在數據依賴關系的不允許重排序。
3)無法通過Happens-before原則推到出來的,才能進行指令的重排序。

3、重排序分為以下 3 種:

  • 編譯器優化的重排(編譯器在不改變單線程程序語義的前提下,可以重新安排語句的執行順序)
  • 指令并行的重排(現代處理器采用了指令級并行技術ILP將多條指令重疊執行。如果不存在數據依賴性,處理器可以改變語句對應機器指令的執行順序)
  • 內存系統的重排(由于處理器使用緩存和讀/寫緩沖區,這使得加載和存儲操作看上去可能是在亂序執行)

注意:

  • 單線程環境里面確保程序最終執行的結果和代碼執行的結果一致。
  • 處理器在進行重排序時必須考慮指令之間的數據依賴性。
  • 1.1 內存屏障

    1、為了保證內存可見性,java編譯器在生成指令序列的適當位置會插入內存屏障指令來禁止特定類型的處理器重排序。
    2、JMM把內存屏障指令分為下列四類:

    注:

  • StoreLoad Barriers是一個“全能型”的屏障,它同時具有其他三個屏障的效果。現代的多處理器大都支持該屏障(其他類型的屏障不一定被所有處理器支持)。
  • 執行該屏障開銷會很昂貴,因為當前處理器通常要把寫緩沖區中的數據全部刷新到內存中(buffer fully flush)。
  • 3、由于編譯器和處理器都能執行指令重排序優化,我們可以通過插入內存屏障禁止在內存屏障前后執行重排序優化。內存屏障另一個作用是強制刷出各種 CPU 緩存數據,因此任何 CPU 上的線程都能讀取到這些數據的最新版本。

    1.2 數據依賴

    1、如果兩個操作訪問同一個變量,且這兩個操作中有一個為寫操作,此時這兩個操作之間就存在數據依賴性。
    2、數據依賴分下列三種類型:

    注意:

  • 上面三種情況,只要重排序兩個操作的執行順序,程序的執行結果將會被改變。
  • 編譯器和處理器在重排序時,會遵守數據依賴性,不會改變存在數據依賴關系的兩個操作的執行順序。
  • 這里所說的數據依賴性僅針對單個處理器中執行的指令序列和單個線程中執行的操作。
  • 1.3 as-if-serial語義

    1、as-if-serial語義是指:不管怎么重排序,單線程程序的執行結果不能被改變。
    2、編譯器,runtime 和處理器都必須遵守as-if-serial語義,給我們創建了一個幻覺:單線程程序是按程序的順序來執行的。
    3、as-if-serial語義使單線程程序員無需擔心重排序會干擾他們,也無需擔心內存可見性問題。

    double pi = 3.14; //A double r = 1.0; //B double area = pi * r * r; //C A和C之間,B和C之間存在數據依賴關系,因此指令序列中,C不能被重排序到A和B之前。

    2 final的內存含義

    1、被final修飾的變量內存語義如下:

    • JMM禁止把Final域的寫,重排序到構造器的外部。
    • 在一個線程中,初次讀該對象和讀該對象下的Final域,JMM禁止處理器重新排序這兩個操作。

    2、final語義在處理器中的實現:

    • 會要求編譯器在final域的寫之后,構造函數return之前插入一個StoreStore障屏。
    • 讀final域的重排序規則要求編譯器在讀final域的操作前面插入一個LoadLoad屏障。

    3 Happen-Before原則

    1、Happen-Before被翻譯成先行發生原則,意思就是當A操作在B操作之前,那么A操作的影響B也會知道。“影響”包括修改了內存中的共享變量的值、發送了消息、調用了方法等。

    2、Happen-Before的規則

    • 程序次序規則(Program Order Rule):在一個線程內,程序的執行規則跟程序的書寫規則是一致的,從上往下執行。
    • 管程鎖定規則(Monitor Lock Rule):一個Unlock的操作肯定先于下一次Lock的操作。這里必須是同一個鎖。同理我們可以認為在synchronized同步同一個鎖的時候,鎖內先行執行的代碼,對后續同步該鎖的線程來說是完全可見的。
    • volatile變量規則(volatile Variable Rule):對同一個volatile的變量,先行發生的寫操作,肯定早于后續發生的讀操作。
    • 線程啟動規則(Thread Start Rule):Thread對象的start()方法先行發生于此線程的每一個動作。
    • 線程中止規則(Thread Termination Rule):Thread對象的中止檢測(如:Thread.join(),Thread.isAlive()等)操作,必行晚于線程中所有操作。
    • 線程中斷規則(Thread Interruption Rule):對線程的interruption()調用,先于被調用的線程檢測中斷事件(Thread.interrupted())的發生。
    • 對象中止規則(Finalizer Rule):一個對象的初始化方法先于一個方法執行Finalizer()方法。
    • 傳遞性(Transitivity):如果操作A先于操作B、操作B先于操作C,則操作A先于操作C。

    線程安全性保證

    1、工作內存與主內存同步延遲現象導致可見性問題

    • 可以使用 synchronzied 或 volatile 關鍵字解決,它們可以使用一個線程修改后的變量立即對其他線程可見。

    2、對于指令重排導致可見性問題和有序性問題

    • 可以利用 volatile 關鍵字解決,因為 volatile 的另一個作用就是禁止指令重排序優化。

    總結

    以上是生活随笔為你收集整理的JMM理论二:相关概念——重排序、内存屏障、数据依赖、as-if-serial、final、Happen-Before的全部內容,希望文章能夠幫你解決所遇到的問題。

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