寫這篇文章的目的,是在交流中發現有的同窗對於volatile的happens-before規則並不太清楚,本文針對對於JMM內存模型的原子性、有序性、可見性等概念有必定了解但對於volatile理解有些模糊的同窗,大約花費7分鐘左右時間緩存
由一個問題開始:ReentrantLock是如何實現與synchronized鎖相同的內存可見性語義的?即:synchronized鎖內操做的共享變量值修改在鎖被釋放後可以保證被其餘線程當即看到,ReentrantLock鎖可以保證嗎,是如何保證的?bash
固然可以保證,不然就談不上是同步鎖,如何保證的正是本文要談的內容微信
class ReorderExample {
int a = 0;
boolean flag = false;
public void writer() {
a = 1; // 1
flag = true; // 2
}
public void reader() {
if (flag) { // 3
int i = a * a; // 4
}
}
}
複製代碼
cpu緩存模型 多線程
JVM內存模型架構
緩存一致性協議 解決緩存不一致問題,一般來講有如下2種方法:
1)經過在總線加LOCK#鎖的方式(效率過低)
2)經過緩存一致性協議(核心思想:當CPU寫數據時,若是發現操做的變量是共享變量,且在其餘CPU中也存在該變量的副本,會發出信號通知其餘CPU將該變量的緩存行置爲無效狀態,後續當其餘CPU須要讀取這個變量時,發現本身緩存中緩存該變量的緩存行是無效的,就會從內存從新讀取)
3)緩存一致性協議不能徹底保證內存可見性,由於爲了提高性能,存在store buffer(存儲緩存)、invalidate queue(失效隊列)等結構,致使內存可見性受影響,由此引出了內存屏障
4)不深究細節(細節我也不太懂),具體請搜索MESI及爲何須要內存屏障app
內存屏障性能
lock addl $0x0,(%rsp)
總結:多線程亂序狀況彙總優化
爲了保證多線程程序執行的正確性,JMM定義了happens-before規則,重排序須要遵照happens-before規則spa
happens-before規則操作系統
volatile底層實現正是藉助內存屏障和緩存一致性協議保障了happens-before規則
回到最初的問題,ReentrantLock如何實現鎖的內存可見性語義?
class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
x = 42;
v = true;
}
public void reader() {
if (v == true) {
//uses x - guaranteed to see 42.
}
}
}
複製代碼