写这篇文章的目的,是在交流中发现有的同窗对于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.
}
}
}
复制代码