什么是Java内存模型中的happens-before
Java內(nèi)存模型JMM
Java內(nèi)存模型(即Java Memory Model , 簡稱JMM),本身是一種抽象的概念,并不真實存在,它描述的是一組規(guī)則或規(guī)范,通過這組規(guī)范定義了程序個各個變量(包括實例字段,靜態(tài)字段和構(gòu)成數(shù)組對象的元素)的訪問方式
?
由于JVM運行時程序的實體是線程,而每個線程創(chuàng)建時,而JVM都會為其創(chuàng)建一個工作內(nèi)存,有一些地方叫做棧空間,用于存儲線程私有的數(shù)據(jù),而Java內(nèi)存模型中規(guī)定所有的變量都保存在主內(nèi)存中,主內(nèi)存是共享內(nèi)存區(qū)域,所以線程都可以訪問。但線程對變量的操作,則讀取和賦值等,必須在工作內(nèi)存中進行。首先從主內(nèi)存中拷貝變量到工作內(nèi)存中,然后對變量進行操作,操作完成后,再將變量寫回到主內(nèi)存中。注意:線程是不能直接操作主內(nèi)存的變量,工作內(nèi)存中就存在主內(nèi)存變量的副本。因此每個線程都不能互相訪問對方的工作內(nèi)存,所以線程之間的通信必須通過主內(nèi)存去進行通信。
?
JMM中的住內(nèi)存和工作內(nèi)存
JVM中的主內(nèi)存
1、存儲Java實例對象
2、包括成員變量、類信息、常量、靜態(tài)變量等
3、屬于數(shù)據(jù)共享的區(qū)域,多線程并發(fā)操作時會引發(fā)線程安全問題
JVM中的工作內(nèi)存
1、存儲當前方法的所有本地變量信息,本地變量對其他線程不可見
2、字節(jié)碼行號指示器,Native方法信息
3、屬于線程私有數(shù)據(jù)區(qū)域,不存線程安全問題
?
JMM與Java內(nèi)存區(qū)域劃分是不同的概念層
1、JMM描述的是一組規(guī)則,圍繞原子性,有序性,可見性展開
2、相似點:存在共享區(qū)域和私有區(qū)域
?
主內(nèi)存與工作內(nèi)存的數(shù)據(jù)存儲類型以及操作方式歸納
1、方法里的基本數(shù)據(jù)類型本地變量將直接存儲在工作內(nèi)存的棧幀結(jié)構(gòu)中
2、引用類型的本地變量:引用存儲在工作內(nèi)存中,實例存儲在主內(nèi)存中
3、成員變量、static變量、類信息均會被存儲在主內(nèi)存中
4、主內(nèi)存共享的方式是線程各拷貝一份數(shù)據(jù)到工作內(nèi)存,操作完成后刷新回主內(nèi)存
?
?
?
指令重排序需要滿足的條件
1、在單線程環(huán)境下不能改變程序運行的結(jié)果
2、存在數(shù)據(jù)依賴關(guān)系的不允許重排序
無法通過happens-before原則推導(dǎo)出來的,才能進行指令的重排序
?
A操作的結(jié)果需要對B操作可見,則A與B存在happens-before關(guān)系
?
?
volatile : JVM提供的輕量級同步機制
1、保證被volatile修飾的共享變量對所有線程總是可見的
2、禁止指令重排序優(yōu)化
volatile的可見性
1、注意,不是線程安全的,只是可見
?
另外一種寫法:
?
volatile變量為何立即可見?
1、當些一個volatile變量時,JMM會把該線程對應(yīng)的工作內(nèi)存中的共享變量值刷新到主內(nèi)存中
2、當讀取一個volatile變量時,JMM會把該線程對應(yīng)的工作內(nèi)存設(shè)置為無效
?
volatile如何禁止重排優(yōu)化
內(nèi)存屏障
1、保證特定操作的執(zhí)行順序
2、保證某些變量的內(nèi)存可見性
通過插入內(nèi)存屏障指令禁止在內(nèi)存屏障前后的指令執(zhí)行重排序優(yōu)化
強制刷出各種cpu的緩存數(shù)據(jù),因此任何CPU上的線程都能讀取到這些數(shù)據(jù)的最新版本
?
?
上面的操作,看上去沒有問題,但是還是有隱患,有可能會有指令重排序之后,導(dǎo)致的問題。
?
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/vingLiu/p/10677428.html
總結(jié)
以上是生活随笔為你收集整理的什么是Java内存模型中的happens-before的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。