volatile原理和语义

volatile

原因

最大化的利用 CPU 提升性能,从硬件、操作系 统、编译器等方面都做出了很多的优化

1. CPU 增加了高速缓存==== 可见性

2. 操作系统增加了进程、线程。通过 CPU 的时间片切换最 大化的提升 CPU 的使用率 ==== 原子性

3. 编译器的指令优化,更合理的去利用好 CPU 的高速缓存 === 有序性

可看https://blog.csdn.net/a_higher/article/details/109728467

解决方案

1.总线加锁(粒度太大)

2.MESI

 a.读操作:不做任何事情,把Cache中的数据读到寄存器

 b.写操作:发出信号通知其他的CPU讲改变量的Cache line置为无效,其他的CPU要访问这个变量的时候,只能从内存中获取

java内存模型

  1. 主存中的数据所有线程都可以访问(共享数据)
  2. 每个线程都有自己的工作空间,(本地内存)(私有数据)
  3. 工作空间数据:局部变量、内存的副本
  4. 线程不能直接修改内存中的数据,只能读到工作空间来修改,修改完成后刷新到内存

volatile作用

保证有序性和可见性

  • 对共享变量的修改,其他的线程马上能感知,但不能保证原子性

实现原理

   借助了CPU的lock指令。在生成汇编代码时会在volatile修饰的共享变量进行写操作的时候会多出Lock前缀的指令,在读写的时候插入内存屏障。从而使得:将当前处理器缓存行的数据写回系统内存;这个写回内存的操作会使得其他CPU 里缓存了该内存地址的数据无效,当处理器发现本地缓存失效后,就会从内存中重读该变量数据,即可以获取当前最新值。这样volatile变量通过这样的机制就使得每个线程都能获得该变量的最新值

内存屏障

      通过禁止指令重排序来实现,也就是加内存屏障,有的处理器这么处理,有的不是

  • 在每个volatile写操作的后面插入一个StoreStore屏障,防止写volatile与后面的写操作重排序。
  • 在每个volatile写操作的后面插入一个StoreLoad屏障,防止写volatile与后面的读操作重排序。
  • 在每个volatile读操作的后面插入一个LoadLoad屏障,防止读volatile与后面的读操作重排序。
  • 在每个volatile读操作的后面插入一个LoadStore屏障,防止读volatile与后面的写操作重排序。

volatile写-读的内存语义(实现mesi)

  • 只有当线程T对变量V执行的前一个动作是load的时候,线程T才能对变量V执行use动作;并且,只有当线程T对变量V执行的后一个动作是use的时候,线程T才能对变量V执行load动作。线程T对变量V的use动作可以认为是和线程T对变量V的load、read动作相关联,必须连续一起出现(这条规则要求在工作内存中,每次使用V前都必须先从主内存刷新最新的值,用于保证能看见其他线程对变量V所做的修改后的值)。
  • 只有当线程T对变量V执行的前一个动作是assign的时候,线程T才能对变量V执行store动作;并且,只有当线程T对变量V执行的后一个动作是store的时候,线程T才能对变量V执行assign动作。线程T对变量V的assign动作可以认为是和线程T对变量V的store、write动作相关联,必须连续一起出现(这条规则要求在工作内存中,每次修改V后都必须立刻同步回主内存中,用于保证其他线程可以看到自己对变量V所做的修改)。

这里的1,2参考https://blog.csdn.net/qq_33808244/article/details/100836342

意思如下:

  • volatile写的内存语义:当写线程写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。
  • volatile读的内存语义:当读线程读一个volatile变量时,JMM会把该线程对应的本地内存置为无效,线程接下来将从主内存读取共享变量。

volatile重排序语义(happens-before)

  • 假定动作A是线程T对变量V实施的use或assign动作,假定动作F是和动作A相关联的load或store动作,假定动作P是和动作F相应的对变量V的read或write动作;类似的,假定动作B是线程T对变量W实施的use或assign动作,假定动作G是和动作B相关联的load或store动作,假定动作Q是和动作G相应的对变量W的read或write动作。如果A先于B,那么P先于Q(这条规则要求volatile修饰的变量不会被指令重排序优化,保证代码的执行顺序与程序的顺序相同

使用场景

状态标志(开关)

DCL

happen-before

与synchronize的区别

使用上的区别

Volatile只能修饰变量,synchronized只能修饰方法和语句块

对原子性的保证

synchronized可以保证原子性,Volatile不能保证原子性

对可见性的保证

都可以保证可见性,但实现原理不同

Volatile对变量加了lock,synchronized使用monitorEnter和monitorexit  monitor  JVM

对有序性的保证

Volatile能保证有序,synchronized可以保证有序性,但是代价(重量级)并发退化到串行

其他

synchronized引起阻塞

Volatile不会引起阻塞

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值