文章目录
volatile在JVM内存交互中的操作
只是做一个简单的记录 ^_^
JMM
- 主内存(共享): 本地方法区 + 堆
- 工作内存(线程私有): 栈 + 寄存器(程序计数器 + CPU高速缓存区)
- 几个规则:
- 所有变量都会存在主内存中,工作内存会保存其中部分变量的拷贝
- 线程对变量的操作必须在工作内存中进行,不能直接读写主内存的变量
- 不同线程的工作内存是私有的,不能相互直接访问,必须通过主内存传递
- 示意图
JVM内存屏障(JVM规范)
- JVM内存屏障(保证有序)
- StoreStore
- StoreLoad
- LoadLoad
- LoadStore
- volatile在JVM层的抽象
StoreStoreBarrier volatile变量的写操作 StoreLoadBarrier LoadLoadBarrier volatile变量的读操作 LoadStoreBarrier
- volatile变量的写操作
happens-before
于这个volatile变量的读操作
JVM内存交互操作(Hotspot)
- JVM定义了8种操作(原子)来完成主内存与工作内存之间的交互
read
: 读取,将变量从主内存传到工作内存,接着将执行loadload
: 载入,将read操作拿到的变量放到工作内存的变量use
: 使用,将工作内存的变量传给执行引擎assign
: 赋值,将执行引擎得到的值赋值给工作内存的变量store
: 存储,将工作的内存变量的值传到主内存中,接着将执行writewrite
: 写入,将store操作拿到变量放到主内存的变量lock
: 锁定,将主内存变量标识为线程独占状态unlock
: 解锁,将主内存变量解除线程独占状态,其后可以被其他线程锁定
volatile在硬件层的操作(Hotspot+Windows)
- volatile会触发lock/unlock,在硬件层的操作流程大致如下
- lock -> 锁住主内存变量a,当前线程独占
- 变量a -> store进入主内存 -> wirte给主内存的变量a
- unlock -> 解除独占状态
- lock操作会触发MESI(IntelCPU)缓存一致性协议:CPU总线嗅探机制被触发 -> 其他线程的该变量a失效 -> 其他线程重新从主内存获取变量a
示例-非volatile修饰的变量赋值操作
- 代码示例
private static int a = 10; public static void main(String[] args) { new Thread(() -> { a = 15; }).start(); }
- 示意图
-------主内存---------|-------工作内存---------|---------CPU-------- a=10 --read-->--load--> a=10 --use--> 计算 a=15 <--assign-- a=15 <--write--<--store--
示例-volatile修饰的变量赋值操作(lock/unlock)
- 代码示例
private static volatile int a = 10; public static void main(String[] args) { new Thread(() -> { a = 15; }).start(); }
- 示意图
-------主内存---------|-------工作内存---------|---------CPU-------- a=10 --read-->--load--> a=10 --use--> 计算 a=15 <--assign-- -------------lock------------ a=15 <--write--<--store-- ------------unlock-----------