invokehelper函数读取内存冲突_十年程序员浅谈并发:同步原语final、volatile的内存语义...

先介绍两个概念this逃逸和内存屏障

this逃逸

一个小栗子:

9ee7ff0c5c992cd993691c838ade7b50.png

this逃逸示例

步骤1和步骤2之前没有重排序的限制规定,因此这两个操作是可以重排序的。如果出现了重排序那么执行”read”方法的线程就有可能读到final变量初始化之前的值,造成final变量未正确初始化。

另外在构造函数中注册事件监听,在构造函数中启动新线程都有可能会引发”this逃逸”。

在构造函数返回之前,其他线程就持有了该对象的引用,这种情况就叫this逃逸。调用尚未构造完成的对象的方法可能引发错误。

内存屏障指

内存屏障(memory barriers)也成为内存栅栏,是一组处理器指令,对内存操作的顺序进行限制,大多数现代计算机为了提高性能而采取乱序执行这使得内存屏障成为必须。JMM内存语义底层是通过memory barriers实现的。

1、LoadLoad Barriers:示意指令"Load1; LoadLoad; Load2",保证Load1先读取完毕,再执行Load2及后续读取指令。

2、StoreStore Barriers:示意指令"Store1; StoreStore; Store2",保证Store1先刷新到内存(对其他处理器可见),再执行Store2及后续写入操作。

3、LoadStore Barriers:示意指令"Load1; LoadStore; Store2",保证Load1先读取完毕,再执行Store2及后续写入指令刷新到内存。

4、StoreLoad Barriers:示意指令"Store1; StoreLoad; Load2",保证Store1先刷新到内存(对其他处理器可见),再执行Load2及后续读取指令。

在大多是处理器中,会先执行完屏障前的所有读写指令,再执行屏障后的内存访问指令。

final语义

重排序

JMM对final的重排序做了特殊的规定,并且在JSR-133做了增强,编译器和处理器在对final域进行重排序时候,都要遵循如下规则:

1、在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。

禁止编译器重排序:编译器不能将final域的写操作重排序到构造函数之外;

禁止处理器重排序:编译器会在final与写之后,构造函数return之前插入个StoreStore屏障,用来禁止处理器将final域的写操作重排序到构造函数之外;

2、初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。

读对象引用,读对象的final域 这两个操作不能重排序。

3、在构造函数内对一个final引用的对象的成员域的写入,与随后在构造函数外把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。如下代码s1处和s2禁止进行重排序:

d8f990df695d7e8c31d98a30aadc542e.png

可见性

final修饰的变量作为不可变变量,只要对象是正确构造的(没有this逃逸发生),不需要任何同步措施就可以保证任何线程都能读到变量在构造函数中被初始化之后的值。

volatile语义

原子性

volatile是否保障原子性是个有争议的话题,32位的JDK中volatile修饰后的long和double也具有原子性。但是volatile int i=0;i++;就不具备原子性,因此可以理解为对单次volatile变量的读写操作具有原子性,复合操作(如i++)不具有原子性。

重排序

为了实现volatile的语义,JMM限制了volatile的编译器重排序和处理器重排序,volatile变量编译器重排序规则:

59fe7c36120c51d44a8877b46280227e.png

编译器会在volatile写操作前后插入StoreStore Barriers和StoreLoad Barriers,volatile读操作前后插入LoadLoad Barriers和LoadStore Barriers。通过插入内存屏障来限制处理器对volatile进行重排序。

volatile与可见性

通过volatile读写操作前后所插入的memory barriers就能够看出,volatile变量能够保证可见性。

小结

1、JMM保证final变量初始化时的有序性、禁止编译器和处理器重排序。

2、final作为不可变对象,正确初始化后(没有this逃逸),能够保障可见性。

3、volatile能够保障单次操作的原子性

4、volatile能够保障变量的可见性

bd8ce9c1e7aa3498ace07b27e33eddc0.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值