volatile

 

JMM内存模型

volatile可见性底层是实现原理

    

底层实现主要是通过汇编lock前缀指令,它会锁定这块内存区域的缓存(缓存行锁定)并写回到主内存

lock指令:

1)将当前处理器缓存行的数据立即写回到系统内存。

2)这个写回内存的操作回引起其他CPU里面缓存了该内存地址的数据无效(MESI协议)

3)提供内存屏障功能,使lock前后指令不能重排序(lock前缀:lock指令不是 一种内存屏障,但是它能完成类似内存屏障的功能)

 

原子性操作流程:

 

 

 先经过总线,只要经过总线就会触发线程1的监控就会将自己缓存的值失效,此时线程2还没有写入主内存,线程1失效,再次从主内存获取内容又获取到 false那怎么办?

加缓存锁,对内存的修改特别快,所以效率高,并不会等待很长时间,在sotre时候就开始加锁此时线程1在去主内存获取值发现加锁了就需要等待线程2 unlock才能获取到值,伪代码:Store (lock initFlag=true,wirte(主内存))unlock

volatile为什么不能保证原子性? ,存在数据丢失

Volatile保证可见性与有序性,但是不保证原子性,保证原子性则需要借助synchronized锁机制来实现。

线程1和线程2同时读取到值都是0,线程1开始执行++ ,线程1是值=1,还未write到主内存,线程2也开始++,线程1写入主内存,线程2失效,再次读取结果为1,线程2再次++,结果为2

  

 

volatile关键字增加了实例变量在多个线程之间的可见性,单volatile不支持原子性 

volatile多个线程中可以感知实例变量被改了,并且可以获取最新的值使用,多线程读取共享便利是可以获取最新值使用。

volatile不处理数据的原子性,只是强制对数据的读写及时影响到住主内存

1.保证此变量对所有的线程的可见性,这里的“可见性”,如本文开头所述,当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存来完成。

2.禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障;

原子性:如果你了解事务,那这个概念应该好理解。原子性通常指多个操作不存在只执行一部分的情况,如果全部执行完成那没毛病,如果只执行了一部分,那对不起,你得撤销(即事务中的回滚)已经执行的部分。

可见性:当多个线程访问同一个变量x时,线程1修改了变量x的值,线程1、线程2...线程n能够立即读取到线程1修改后的值。

有序性:即程序执行时按照代码书写的先后顺序执行。在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。

 

 指令重排:在不影响单线程程序执行结果的前提下,计算机为了最大限度的发挥机器性能,会对机器指令重排优化

 

 

posted @ 2019-08-12 19:07  暖暖-木木  阅读(148)  评论(0编辑  收藏  举报