volatile(二)

volatile内存语义

volatile的特性

  • 可见性:对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入
  • 原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性(基于这点,我们通过会认为volatile不具备原子性)。volatile仅仅保证对单个volatile变量 的读/写具有原子性,而锁的互斥执行的特性可以确保对整个临界区代码的执行具有原子性。 64位的long型和double型变量,只要它是volatile变量,对该变量的读/写就具有原子性。
  • 有序性:对volatile修饰的变量的读写操作前后加上各种特定的内存屏障来禁止指令重排序来保障有序性。 在JSR-133之前的旧Java内存模型中,虽然不允许volatile变量之间重排序,但旧的Java内存模型允许volatile变量与普通变量重排序。为了提供一种比锁更轻量级的线程之间通信的机制,JSR-133专家组决定增强volatile的内存语义: 严格限制编译器和处理器对volatile变量与普通变量的重排序,确保volatile的写-读和锁的释放-获取具有相同的内存 语义

volatile写-读的内存语义

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

volatile可见性实现原理

  • JMM内存交互层面

    volatile修饰的变量,其read,load,use,assign,store,write必须是连续的,也就是修改后必须立即同步回主内存,使用时必须立即从主内存刷新,由此保证volatile对变量操作在多线程环境中的可见性。

  • 硬件层面

    通过Lock前缀指令,锁定变量缓存行区域,并写回到主内存,也就是"缓存锁定",缓存一致性机制会阻止同时修改被两个以上处理器缓存的内存区域数据。

  • volatile在hotspot的实现

    (字节码解释器实现)

    可以看到,程序会先判断这个变量又没有没volatile修饰,有的话则调用OrderAccess:😗*storeload()**方法。

    storeload,也就是JVM层面的内存屏障(要与处理器的内存屏障区分开哦~),storeload方法内部调用了fence方法,fence方法先判断处理器是否为多核,如果为多核则调用==lock; addl $0,0(%%rsp)==指令。

    这个lock前缀指令并非内存屏障指令,由于它可以起到内存屏障的效果,还可以使缓存失效,并且其性能也要优于mfence内存屏障,所以选用它。那么lock前缀指令究竟有哪些作用呢

    • 确保后续指令执行的原子性。在Pentium及之前的处理器中,带有lock前缀的指令在执行期间会锁住总线,使得其它处理器暂时无法通过总线访问内存,很显然,这个开销很大。在新的处理器中,Intel使用缓存锁定来保证指令执行的原子性,缓存锁定将大大降低 lock前缀指令的执行开销。
    • LOCK前缀指令具有类似于内存屏障的功能,禁止该指令与前面和后面的读写指令重排序。
    • LOCK前缀指令会等待它之前所有的指令完成、并且所有缓冲的写操作写回内存(也就是将store buffer中的内容写入内存)之后才开始执行,并且根据缓存一致性协议,刷新 store buffer的操作会导致其他cache中的副本失效。

什么是指令重排序

Java语言规范规定JVM线程内部维持顺序化语义。也就是说只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码顺序不一致,此过程叫指令的重排序

指令重排序的意义:JVM能根据处理器特性(CPU多级缓存系统、多核处理器等)适当的对机器指令进行重 排序,使机器指令能更符合CPU的执行特性,最大限度的发挥机器性能

在编译器与CPU处理器中都能执行指令重排优化操作

在这里插入图片描述

volatile重排序规则

在这里插入图片描述

volatile禁止重排序场景

  • 第二个操作是volatile写,不管第一个操作是什么都不会重排序
  • 第一个操作是volatile读,不管第二个操作是什么都不会重排序
  • 第一个操作是volatile写,第二个操作是volatile读,也不会重排序

JMM内存屏障插入策略

  • 在每个volatile写操作的前面插入一个StoreStore屏障
  • 在每个volatile写操作的后面插入一个StoreLoad屏障
  • 在每个volatile读操作的后面插入一个LoadLoad屏障
  • 在每个volatile读操作的后面插入一个LoadStore屏障
    在这里插入图片描述
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SONNIE在路上

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

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

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

打赏作者

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

抵扣说明:

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

余额充值