volatile 关键字的作用主要/特性是:
- 保证变量可见性
- 限制指令重排
volatile 关键字涉及的知识点可谓是比较多的。
首先,变量可见性与 Java 内存模型(JMM, Java Memory Model)有关。
对于一个共享变量(比如静态变量),它保存在所有线程共享的主内存中,而每个线程的工作内存都有一个该变量的“副本”,线程读写变量就涉及到两个内存中值的传递。
现在,我们先用 A 线程修改共享变量,再用 B 线程读取变量值。
根据 happens-before 原则,A 线程修改在前,B 线程读取在后,所以 B 线程读取到的应是 A 线程修改后的变量。
但事实是,B 线程可能在 A 线程修改工作内存而还没有刷回主内存时读取到旧的变量值。
而 volatile 变量会保证工作内存和主内存的同步,而不会出现上述问题。
要注意的是,volatile 只保证变量可见性,但并非线程安全的,也没有原子性,使用时通常有以下一些限制:
- 运行结果不依赖变量当前值。i++ 这种操作就不能有
- 不要与其他状态变量共同参与不变约束。两个变量关系作为循环条件也不行
- 一写多读。只有单一线程修改变量
另外,volatile 还限制指令重排。
指令重排即对执行的指令进行重新排序,目的是效率优化。但指令重排只保证单线程下结果不变,多线程下可能影响执行结果。
volatile 引入 Memory Barrier(内存屏障/内存栅栏/栅栏指令)约束了重排,以确保结果的正确性。
总之,volatile 如其字面含义所指的一样,表示修饰的变量是易变的,因此内部将通过一系列手段确保总是使用其最新值。