Java内存模型与happens-before原则
Java內存模型
Java內存模型不同于Jvm內存模型,Java內存模型(JMM)規定了JVM必須遵循一組最小保證,這組保證規定了對變量的寫入操作在何時將于其他線程可見。
在Java虛擬機規范中試圖定義一種Java內存模型(Java Memory Model,JMM),JVM通過在適當的位置插入內存柵欄來屏蔽JMM和各個硬件平臺和操作系統的內存訪問差異,以實現讓Java程序在各種平臺下都能達到一致的內存訪問效果。Java內存模型并沒有限制執行引擎使用處理器的寄存器或者高速緩存來提升指令執行速度,也沒有限制編譯器對指令進行重排序。也就是說,在java內存模型中,也會存在緩存一致性問題和指令重排序的問題。
Java內存模型規定所有的變量都是存在主存當中(類似于前面說的物理內存),每個線程都有自己的工作內存(類似于前面的高速緩存)。線程對變量的所有操作都必須在工作內存中進行,而不能直接對主存進行操作。并且每個線程不能訪問其他線程的工作內存。
如圖:
一,重排序
再沒有充分同步的程序中,如果調度器采用不恰當的方式來交替執行不同線程的操作,那么將導致不正確的結果。更糟糕的是,JMM還使得不同線程看到的操作執行順序是不同的,從而導致在缺乏同步的情況下,要推斷操作的執行順序更加復雜,各種使得操作延遲或者砍死亂序執行的不同原因,都可以稱為“重排序”
將緩存刷新到主內存的不同時序也可能會導致重排序。
重排序的基礎是前后語句不存在依賴關系時,才有可能發生指令重排序。
內存柵欄會屏蔽重排序
兩個操作之間存在happens-before關系,并不意味著Java平臺的具體實現必須要按照happens-before關系指定的順序來執行。如果重排序之后的執行結果,與按happens-before關系來執行的結果一致,那么這種重排序并不非法(也就是說,JMM允許這種重排序)
二,happens-before
happens-before原則是指如果A和B滿足這個happens-before原則,則可以保證操作B的線程可以看到操作A的結果。
當一個變量被多個線程讀取并且至少被一個線程寫入時,如果在讀操作和寫操作之間沒有按照H-B原則來排序,就會產生數據競爭問題,在正確同步的程序中不存在數據競爭,并且會表現出串行一致性。
1,程序順序原則
單線程中,寫在前面的操作A會在寫在后面的操作B之前執行。
2,鎖原則
在鎖上的解鎖操作必須在鎖上的加鎖操作之前執行。
3,volatile變量原則
對volatile變量的寫入操作必須在對該變量的讀操作之前執行。
4,線程啟動原則
在一個線程上,start操作必須在該線程執行任何操作之前執行。
5,線程關閉原則
線程中任何操作都必須在其他線程檢測到該線程已經結束之前執行。
6,線程中斷原則
當一個線程在另一個線程調用interrupt時,必須在被中斷線程檢測到interrupt調用之前執行。‘’
7,終結器規則。
對象的構造函數必須在啟動該對象的終結器之前執行完成。
8,傳遞性
如果操作A H-B 操作B,操作B H-B 操作C 則 操作A H-B 操作C
如果2個在不同線程的操作不滿足H-B原則,則無法推斷一個操作是否一定在另一個操作之前。
如:
這里,在多個線程來調用時,因為不滿足H-B,所以第一個線程調用時,已經初始化了resource,沒法保證第二個線程來時,獲取到的resource到底是拿到的null還是一個失效值。
三,借助同步
由于H-B排序功能很強大,因此有時候可以“借助”現有同步機制的可見性屬性。
“借助同步”技術是指借助于現有的H-B原則,來確保對象X的可見性,而不是為了發布X而創建一個H-B順序。
在類庫中提供的其他H-B順序:
四,并發編程的三個問題
1,原子性
一個操作要么全部執行,要么不執行。
JAVA中原子性靠synchronized和Lock來實現,或者native方法的cas等
2,可見性
多個線程訪問一個變量時,一個線程修改后其他線程可以立即看到這個值的改變。
Java提供了volatile關鍵字來保證可見性
3,有序性
程序執行的順序按照代碼的先后順序執行。
Java中保證了單線程下看起來有序(as if serial),不保證多線程下有序。
因為在Java內存模型中,允許編譯器和處理器對指令進行重排序,但是重排序過程不會影響到單線程程序的執行,卻會影響到多線程并發執行的正確性。
在Java里面,可以通過volatile關鍵字來保證一定的“有序性”(具體原理在下一節講述)。另外可以通過synchronized和Lock來保證有序性,很顯然,synchronized和Lock保證每個時刻是有一個線程執行同步代碼,相當于是讓線程順序執行同步代碼,自然就保證了有序性。
另外,Java內存模型具備一些先天的“有序性”,即不需要通過任何手段就能夠得到保證的有序性,這個通常也稱為 happens-before 原則。如果兩個操作的執行次序無法從happens-before原則推導出來,那么它們就不能保證它們的有序性,虛擬機可以隨意地對它們進行重排序。
總結
以上是生活随笔為你收集整理的Java内存模型与happens-before原则的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 线程池工作原理
- 下一篇: Java中 synchronized 关