happen-before原则的理解
前言
在程序執行時,為了提高性能,編譯器和處理器會對指令進行重排序。
為了明確定義多線程場景下重排序的問題(可見性、有序性、原子性),Java引入了JMM(Java Memory Model),也就是Java內存模型。JMM為JAVA程序員提供了8條規則,即happen-before原則。根據happen-before原則,就可以在不理解復雜的重排序規則情況下,解決因重排序而導致的多線程間可見性、有序性等問題。
happen-before原則
兩個操作具有happen-before關系,并不意味著前一個操作比后一個操作先執行!happen-before僅要求前一個操作的執行結果對后一個操作可見。
可以將happen-before原則分兩部分理解,單線程與多線程環境下的happen-before。單線程下通過語義分析數據依賴關系,編譯器和處理器可以合理的優化我們的代碼。但是多線程情況下不同線程間的數據依賴關系有我們定義,處理器與編譯器都無法通過分析感知。
happen-before原則定義了某些特定場景下多線程間的數據依賴關系。即happen-before原則是對單線程環境下的指令重排序以及多線程環境下的線程間數據的一致性進行的約束。
對八條原則的理解來自:牛有肉:happen-before原則的理解
(1) 單線程happen-before原則:在同一個線程中,書寫在前面的操作happen-before后面的操作。
首先是單線程的 happen-before ,前面的操作產生的結果必須對后面的操作可見。而不是前面的操作必須先于后面的操作執行,比如按照 as-if-serial 語義,沒有數據依賴的兩條指令是可以進行重排序的。而這種情況對于 happen-before 原則來說,因為兩條指令都沒有產生對方需要的結果,而不需要對對方可見,及時執行順序被調轉也是符合 happen-before 原則的。
(2) 鎖的happen-before原則:同一個鎖的unlock操作happen-before此鎖的lock操作。
個人理解強調的是解鎖操作在多線程環境的可見性。一個線程進行了解鎖操作,對于晚于該操作的加鎖操作必須能夠及時感應到鎖的狀態變化。解鎖操作的結果對后面的加鎖操作一定是可見的,無論兩個是否在一個線程。
(3) volatile的happen-before原則: 對一個volatile變量的寫操作happen-before對此變量的任意操作。
對 volatile 變量的寫操作的結果對于發生于其后的任何操作的結果都是可見的。x86 架構下volatile 通過內存屏障和緩存一致性協議實現了變量在多核心之間的一致性。
(4) happen-before的傳遞性原則: 如果A操作 happen-before B操作,B操作happen-before C操作,那么A操作happen-before C操作。
happen-before 可以說是兩項操作之間的偏序關系,滿足偏序關系的各項性質,我們都知道偏序關系中有一條很重要的性質:傳遞性,所以happen-before也滿足傳遞性。這個性質非常重要,通過這個性質可以推導出兩個沒有直接聯系的操作之間存在happen-before關系
(5) 線程啟動的happen-before原則:同一個線程的start方法happen-before此線程的其它方法。
start 放法與其它方法可能并沒有數據依賴關系,但是顯而易見的,為了程序的正確性,我們必須做到這一點。start 方法造成的函數副作用必須對其它方法可見。
(6) 線程中斷的happen-before原則:對線程interrupt方法的調用happen-before被中斷線程的檢測到中斷發送的代碼。
interrupt 方法改變的狀態必須對后續執行的檢測方法可見。
(7) 線程終結的happen-before原則:線程中的所有操作都happen-before線程的終止檢測。
為了安全的關閉線程,線程中的方法造成的函數副作用必須對線程關閉方法可見。
(8)對象創建的happen-before原則:一個對象的初始化完成先于他的finalize方法調用。
單線程下對象的創建于銷毀存在數據依賴,該條原則強調的是多線程情況下對象初始化的結果必須對發生于其后的對象銷毀方法可見。
總結
以上是生活随笔為你收集整理的happen-before原则的理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 专项扣除备案流程(专项扣除备案)
- 下一篇: godaddy怎么注册域名(godadd