一.happens-before原則
同一個線程中的,前面的操作 happens-before 后續的操作。(即單線程內按代碼順序執行。但是,在不影響在單線程環境執行結果的前提下,編譯器和處理器可以進行重排序,這是合法的。換句話說,這一是規則無法保證編譯重排和指令重排)。
1. 監視器上的解鎖操作 happens-before 其后續的加鎖操作。(Synchronized 規則)
2. 對volatile變量的寫操作 happens-before 后續的讀操作。(volatile 規則)
3. 線程的start() 方法 happens-before 該線程所有的后續操作。(線程啟動規則)
4. 線程所有的操作 happens-before 其他線程在該線程上調用 join 返回成功后的操作。
5. 如果 a happens-before b,b happens-before c,則a happens-before c(傳遞性)
二.volatile關鍵字的作用
Volatile關鍵字主要用於保證內存可見性和順序性:
1.volatile修飾的變量可以保證一個線程對該變量的寫happens-before 一個線程對該變量的讀
2.Volatile可以用來修飾long和double類型的變量使其以原子方式執行
3.Volatile在雙重檢查加鎖的單例模式中的應用,可以防止重排序

三.volatile關鍵字的實現原理
在java代碼編譯成字節碼時會在volatile修飾的共享變量進行寫操作的時候會多出Lock前綴的指令。
我們知道為了提高處理速度,CPU不直接和內存進行通信,而是先將系統內存的數據讀到內部緩存(L1,L2或其他)后再進行操作,但操作完不知道何時會寫回內存。如果對聲明了volatile的變量進行寫操作,JVM就會向CPU發送一條Lock前綴的指令,將這個變量所在緩存行的數據寫回到系統內存。但是,就算寫回到內存,如果其他處理器緩存的值還是舊的,再執行計算操作就會有問題。所以,在多處理器下,為了保證各個CPU的緩存是一致的,就會實現緩存一致性協議,每個CPU通過嗅探在總線上傳播的數據來檢查自己緩存的值是不是過期了,當處理器發現自己緩存行對應的內存地址被修改,就會將當前CPU的緩存行設置成無效狀態,當CPU對這個數據進行修改操作的時候,會重新從系統內存中把數據讀到處理器緩存里
- Lock前綴的指令會引起CPU緩存寫回內存;
- 一個CPU的緩存回寫到內存會導致其他處理器的緩存失效;
- 當CPU發現本地緩存失效后,就會從內存中重讀該變量數據,即可以獲取當前最新值。
這樣針對volatile變量通過這樣的機制就使得每個線程都能獲得該變量的最新值
volatile相關的理解就寫到這里,如果大家還想詳細的了解volatile可以查閱相關資料或者私信我進行交流。
並發是java中無法避免的問題,基本上java面試都會涉及一些並發相關的問題,尤其是互聯網公司一定會問到,今天就先寫到了這里,下次准備把並發中相關的鎖和並發集合的知識整理一下分享給大家,如果喜歡記得關注我【不愛八阿哥】,有什么問題也可以私信交流,讓我們共同進步。
來源:https://www.toutiao.com/i6656572928701760004/