volatile语义级别分析

https://www.cnblogs.com/keeya/p/9255136.html

1。可见行

2、对变量的读写操作保证原子性,但是不能保证i++这类的操作因为这是三个操作也叫复合操作,这里里面包括了读取值 修改,写回到主内存。可能在前面读的时候拿到了最新的,但是可能其他线程在这个线程修改操作前,进行了修改然后相当于两个线程进行了相同的操作。

volatile读写建立的的happeds-before关系:

      java5也就是JSR-133以后volatile修饰的可以进行线程间通信,从内存语义上说就是volatile的写-读与锁的释放-获取有相同的内存效果:volatile写和 锁的释放有相同的内存语义;volatile读与锁的获取有相同的内存语义。

 

如上图 1 happensbefore 2  3 happends-before4 因为 volatile 修饰flag 所以2 happends before3 所以更具happends-before 传递性所以1 happens-before 4

 

 

volatile 的内存语义:

如下图所示:当A线程对flag有修改操作时,因为volatile的修饰,所以发生修改操作时,嗅探机制,后面有内存锁

 

 

3、volatile语义的实现

重排是指处理器和编译器为了提高代码执行效率进行重新排序,但是当加了volatile后,jmm会对这些编译器和处理器进行屏蔽,如下图

3.1:重排规则表

这个图表示的意思是:两个操作,第一个操作当为普通读写时,第二个操作的普通读写、volatile读都是允许重排的只有volitile写是不可以的。

为了保证volatile语义的实现,所以在编译器生成字节码的时候,会在代码中插入内存屏障,

 

·在每个volatile写操作的前面插入一个StoreStore屏障。

·在每个volatile写操作的后面插入一个StoreLoad屏障。

·在每个volatile读操作的后面插入一个LoadLoad屏障。

·在每个volatile读操作的后面插入一个LoadStore屏障。

内存。

上图中的storestore屏障保证了在这个以后所有之前的普通的操作的值都已经刷新到主内存中,sl保证了后面的volatile不会和当前进行排序。

这里比较有意思的是,volatile写后面的StoreLoad屏障。此屏障的作用是避免volatile写与 后面可能有的volatile读/写操作重排序。因为编译器常常无法准确判断在一个volatile写的后面 是否需要插入一个StoreLoad屏障(比如,一个volatile写之后方法立即return)。为了保证能正确 实现volatile的内存语义,JMM在采取了保守策略:在每个volatile写的后面,或者在每个volatile 读的前面插入一个StoreLoad屏障。从整体执行效率的角度考虑,JMM最终选择了在每个 volatile写的后面插入一个StoreLoad屏障。因为volatile写-读内存语义的常见使用模式是:一个 写线程写volatile变量,多个读线程读同一个volatile变量。当读线程的数量大大超过写线程时, 选择在volatile写之后插入StoreLoad屏障将带来可观的执行效率的提升。从这里可以看到JMM 在实现上的一个特点:首先确保正确性,然后再去追求执行效率。

 

ll禁止下面所有读的普通操作和volitile操作进行重拍,ls禁止下面所有写操作进行重排。

注意,最后的StoreLoad屏障不能省略。因为第二个volatile写之后,方法立即return。此时编 译器可能无法准确断定后面是否会有volatile读或写,为了安全起见,编译器通常会在这里插 入一个StoreLoad屏障。

 

java5以后增强volatile内存语义

 

因此,在旧的内存模型中,volatile的写-读没有锁的释放-获所具有的内存语义。为了提供 一种比锁更轻量级的线程之间通信的机制,JSR-133专家组决定增强volatile的内存语义:严格 限制编译器和处理器对volatile变量与普通变量的重排序,确保volatile的写-读和锁的释放-获 取具有相同的内存语义。从编译器重排序规则和处理器内存屏障插入策略来看,只要volatile 变量与普通变量之间的重排序可能会破坏volatile的内存语义,这种重排序就会被编译器重排 序规则和处理器内存屏障插入策略禁止

 

由于volatile仅仅保证对单个volatile变量的读/写具有原子性,而锁的互斥执行的特性可以 确保对整个临界区代码的执行具有原子性。在功能上,锁比volatile更强大;在可伸缩性和执行 性能上,volatile更有优势。如果读者想在程序中用volatile代替锁,请一定谨慎,具体详情请参 阅Brian Goetz的文章《Java理论与实践:正确使用Volatile变量》

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值