并发编程(5)-volatile内存语义及JMM实现方式

volatile特性
1)可见性 对一个 volatile 变量的读总恩能够看到之前对这个变量的写
2)原子性 对任意单个volatile变量的读写具有原子性,但是对于复合操作 volatile++没有原子性。
疑问: 读为啥能有原子性? 因为缓存一致性协议如果读了一半被修改了,就重新读?

这里A线程写一个volatile变量后,B线程读同一个volatile变量。A线程在写volatile变量之前所有可见的共享变量,在B线程读同一个volatile变量后,将立即变得对B线程可见。这样我们说volatile写具有锁释放的内存语义,volatile读具有锁获取的内存语义

volatile 写的内存语义:当写一个volatile变量时,JMM把该线程对应的本地内存中的共享变量的值刷新到主内存。结合上边的特性应该是写volatile变量后 将所有的本地内存中共享变量都回写到内存中。因为回写一条数据也是写写多条也是写,干脆写多条。
volatile读的内存语义:读一个volatile变量时JMM会吧该线程对应的本地内存设置为无效,线程从主内存中读取共享变量。按照上述理论也是所有的共享变量都无效。都从主内存读
在这里插入图片描述
JMM如何实现volatile内存语义?

为了实现volatile回写内存,前边讲到过通过在编译时插入lock开头指令就能实现。但是有个问题,就是指令重排序的问题,根据上边的写一个volatile变量时,实际上所有的共享变量都要回写到内存,如果计算机对 普通共享变量和volatile共享变量的写进行了重排序。以上述 a =1 ;flag = true;为例(flag 为volatile变量)。如果计算机进行了指令重排序排序后 flag = true;a =1 ;修改flag值得时候 线程中的共享变量都回写到了主内存,但是由于重排序了,变量a本应该回写到内存的值为1,确写成了0 。显然不符合volatile的语义。那怎么避免这种情况呢?就是对于volatile变量的读写前后需要插入内存屏障禁止非法的重排序。为此JMM定义了 volatile重排序规则表如下:
在这里插入图片描述
总结就是:
volatile 写和之前的操作不能重排序
volatile 读和之后的操作不能重排序
volatile 写和后边的volatile读不能重排序

那么怎么能禁止重排序呢?就是插入内存屏障。
根据上边的规则,JMM会在
每个volatile写操作前边插入一个 storestore 屏障 禁止volatile写和之前的写不能重排序。
每个volatile写操作后边插入一个 storeload 屏障 保证volatile写和之后的读不能重排序
每个volatile读操作后边插入一个 loadstore 和loadload 屏障 保证 volatile读后边的读写操作不会冲排序到前边
如此便解决了上边描述的指令重排序问题,实现了JMM约定的volatile语义。

**疑问:**根据规则表 普通读 volatile写 这两个也不能重排序,但是在volatile写前边却未插入loadstore屏障 为啥呢(求大神回答)?

上述内存屏障的插入很保守,在实际的执行中,JMM会根据具体情况省略可以省略的屏障。比如如果volatile写之后没有 volatile读就可以省略 storeLoad屏障。方法结尾的(return之前)的屏障不能省略因为编译器无法判断之后是否还有volatile读写,安全起见不能省略。

JSR-133为什么增强volatile的语义?
在JSR-133之前的java内存模型中,只是不允许volatile共享变量读写的重排序,对于普通共享变量和读写和volatile读/写得重排序是不做限制的(这样就存在我们上边所述的那种问题)。所以在旧内存模型中volatile写没有锁的释放的内存语义。为了提供一种比锁更轻量级的线程之间通信机制,JSR-133专家组才决定增强 volatile内存语义。就是增加内存屏障的插入。避免能破坏volatile内存语义的重排序发生。

volatile只能保证单个变量读/写操作具有原子性,而锁的互斥执行可以确保对整个临界区代码执行具有原子性,功能上锁更强大,但是性能上volatile更有优势。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

catch that elf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值