对volatile关键字的理解

在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比sychronized关键字更轻量级的同步机制

1. 保证多个线程之间的可见性

可见性,是指当一条线程修改了共享变量的值,新值对于其他线程来说是可以立即得知的

解决线程之间可见性, 强制线程每次读取该值的时候都去“主内存”中取值
每个线程都有自己独立的工作区间,为了匹配CPU的运行速度,他们不会直接从内存中读取数据,而是将数据拷贝一份到CPU缓存中(即每个线程自己的工作内存),他们之间的相互交互,是通过内存来完成的。

根据JMM内存模型的8大原子操作,每个线程在j将数据操作完store回主存之前,会加lock指令来锁定内存区域的缓存(缓存行锁定),根据MESI缓存一致性协议,总线通过侦听器发现数据被修改,会立即让其他线程工作内存中不一致的副本立即失效。

等到当前线程将更改后的数据write回主存后,立即执行unlock指令。
image.png

2. 保证了有序性, 禁止指令重排序

指令重排
JVM在编译java代码或者CPU执⾏JVM字节码时,对现有的指令进⾏重新排序,主要⽬的是优化运⾏效率(不改变程序结果的前提)

volatile能够实现禁止指令重排的底层原理:

  • 内存屏障(Memory Barrier):它是一个CPU指令。由于编译器和CPU都能够执行指令重排,如果在指令间插入一条Memory Barrier则会告诉编译器和CPU,任何指令都不能和该条Memory Barrier指令进行重排序,即通过插入内存屏障指令能够禁止重排序 优化
  • 内存屏障的另外一个作用是强制刷新各种CPU的缓存数据,因此任何CPU上的线程都能够读取到这些数据的最新版本。以上两点正好对应了volatile关键字的禁止指令重排序和内存可见性的特点
  • 对volatile变量进行写操作时,会在写操作之后加入一条store屏障指令,将工作内存中的共享变量copy刷新回主内存中;

对volatile变量进行读操作时,会在读操作之前加入一条load的屏障指令,从主内存中读取共享变量

3. 不具备原子性

解决不保证原子性问题:Atomic

用途

适合作为状态标记量
高并发环境下DCL单例模式使用volatile


参考文章:
https://juejin.im/post/5a2b53b7f265da432a7b821c
https://blog.csdn.net/weixin_43232955/article/details/106737169