JVM 之 volatile可见性、禁止指令重排序的JVM实现

volatile (可见性、禁止指令重排序)

介绍思路:volatile是什么?解决了什么问题?怎么实现的?有什么可以扩展的?

volatile是什么?

volatile是java提供的轻量级的锁(在jdk6锁优化前可以说是最轻量级)

volatile解决了什么问题?

  • 可见性:保证变量修改后对所有线程可见
  • 禁止指令重排序:禁止指令重排序对程序并发执行所产生的干扰

volatile怎么实现的?

  • volatile的可见性,是通过 各个线程 对volatile所声明的变量 进行操作前,并不是直接使用工作内存中的主内存副本,而是于主内存中加载最新的数据后再使用。
    volatile修饰的变量值更新后并不是立即对所有线程可见,而是类似懒加载的形式,使用时可见。
  • volatile的禁止指令重排序,是通过设置内存屏障实现的,我理解就是通过内存屏障将代码块中的指令分割为了两部分,以保证内存屏障前的指令全都先于内存屏障后的指令。

内存屏障怎么实现的?干了点啥?

内存屏障实际是通过插入一条lock指令实现的,lock指令会将当前线程的变量值写回主内存,根据可见性,也就是说所有线程中在使用该变量副本前都会同步到此次写入的值。

内存屏障详解(可看可不看)

内存屏障实际是执行了一个"lock"操作(完整指令为:"addl$0x0,(%esp)"(把ESP寄存器的值加0))。

lock的作用是将本处理器的缓存写入了内存,该写入动作也会引起别的处理器或者别的内核无效化(Invalidate)其缓存,

所以这种操作相当于对缓存中的变量做了一次前面介绍Java内存模式中所说的"store和write"操作 [4] 。

所以通过这样一个空操作,可让前面volatile变量的修改对其他处理器立即可见。

volatile实际使用时需注意的点:

volatile的读写性能

  • volatile修饰的变量在读取上与普通变量的读取性能几乎相同,但写入则会慢上一些,因为需要在指令中插入内存屏障。

volatile可见性不适用的场景

  • 运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值。
    例如:volatile i ; i++; i++是出栈 +1 入栈的操作,也就是说在出栈时i是最新值,但+1操作进行时,i的值可能已被其他线程改变,最终导致入栈操作时的i不正确。
  • 变量不需要与其他的状态变量共同参与不变约束。
    例如:volatile boolean flag = true; while(flag){}; 其他线程执行flag=false时,while立即停止。

扩展:对volatile关键字的理解离不开 -> java的内存模型

java的内存模型:

  • java中的所有变量都存储在主内存中
  • java线程会维护一个自身工作内存,其中保存了该线程自己使用到的变量的主内存副本,该线程的所有操作都在工作内存进行(保证了线程间的隔离)

线程间的数据传递怎么进行?

  • 线程间的数据传递通过主内存进行,即线程、工作内存、主内存间的交互进行传递。
    也就是,需要A线程先将变量X的新值刷回主线程,B线程再于主线程内获取到变量X的新值,如此完成线程间的数据传递。
相关推荐
zz-zjx5 小时前
JVM垃圾收集器详解(jdk21+25实战版)
java·开发语言·jvm
工业甲酰苯胺7 小时前
Java并发机制的底层实现原理:从CPU到JVM的全面解析
java·jvm·spring
初级炼丹师(爱说实话版)10 小时前
JVM的classpath
jvm·ide
7哥♡ۣۖᝰꫛꫀꪝۣℋ20 小时前
JVM初识
jvm
凸头1 天前
以AtomicInteger为例的Atomic 类的底层CAS细节理解
java·jvm·算法
初级炼丹师(爱说实话版)1 天前
JVM类的加载
jvm
JAVA学习通1 天前
JDK高版本特性总结与ZGC实践
java·jvm·算法
只想码代码1 天前
什么是程序计数器?
java·jvm
JAVA学习通1 天前
OJ竞赛平台----C端题目列表
java·开发语言·jvm·vue.js·elasticsearch