Java volatile关键字

在面试中,经常会被问到volatile关键字的作用和原理,故而整理出本篇文章进行说明。

(提示:阅读本文需要具备内存操作相关知识,可以看这里

volatile是Java保留的一个关键字,可以用于修饰变量,有以下两个语义:

1. 保证此变量对所有线程的可见性

Java内存模型保证了对于volatile修饰的变量,load和use操作必须连续出现,assign和store操作必须连续出现。这样保证了工作内存每次使用变量时都从主内存刷新最新变量值,每次修改变量后都向主内存写入最新变量值。

但是,需要注意的是,即使如此,volatile也无法保持一致性,因为use操作将变量传递给执行引擎之后的运算不能保证原子性,即使是基础数据类型,也只有访问读写操作具有原子性,数据运算的过程无法保证。所以,虽然从各个线程读写的角度来看数据一致,但实际操作中会存在覆盖运算结果的情况。

2. 禁止指令重排序优化

Java字节码解释为机器指令后,只能保证结果一致,并不能生成的汇编代码机器指令的顺序也和Java代码中一致。在单一线程中,指令重排序不会造成什么问题,但在并发环境下,不做任何操作则无法保证代码按照原有的期望去执行。

volatile关键字修饰的变量会在assign操作对应的指令之后加上一句“lock addl $0x0,(%esp)”(注意这里的lock和内存操作lock无关),语义为对ESP寄存器加0,即一个空操作。这一指令会要求将线程所使用的缓存写入内存,可以理解为将工作内存中的变量写入主内存,即store和write操作。

因为指令重排序要保证结果一致,所以对于这类写回操作不会重排,即“无法越过内存屏障”。

这一规则保证了对于两个volatile变量A和B,若A的use或assign操作先于B,则A的read或write操作也先于B。

应用场景

结合以上所述的两条语义,使用volatile修饰变量可以用于以下场景:

1. 运算结果并不依赖变量当前值(即只依赖于原子性的写操作),或者确保只有单一线程可以修改变量的值;

2. 变量不需要其他状态变量共同参与不变约束。


参考文献:

《深入理解Java虚拟机:JVM高级特性与最佳时间》,第2版,周志明

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值