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把內存屏障指令分為下列四類:
注:
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語義使單線程程序員無需擔心重排序會干擾他們,也無需擔心內存可見性問題。
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的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 以太坊编程入门实战-熊健-专题视频课程
- 下一篇: theos tweak导入自定义类