谈谈Java volatile关键字的用法及原理
Java面试题:谈谈Java volatile关键字的用法及原理?
得分点:
特性、内存语义、实现机制
标准回答:
volatile
是一种Java关键字,用于修饰变量,具有以下特性:
- 可见性:当一个线程修改一个
volatile
变量时,其他线程能够立即看到这个修改。这确保了对volatile
变量的修改对所有线程都是可见的。 - 原子性:对单个
volatile
变量的读写操作是原子的。这意味着每次读写volatile
变量都不会被拆分成多个机器指令,保证了操作的原子性。
volatile
通过影响线程的内存可见性来实现上述特性,它具备如下的内存语义:
- 写内存语义:当写一个
volatile
变量时,Java内存模型(JMM)会将该线程本地内存中的共享变量的值刷新到主内存中,使其对其他线程可见。 - 读内存语义:当读一个
volatile
变量时,JMM会将该线程的本地内存置为无效,从主内存中重新读取共享变量的值,确保了可见性。
volatile
的底层实现依赖于内存屏障(Memory Barrier),这是一种硬件级别的机制,用于禁止特定类型的处理器和编译器重排序操作。在Java中,内存屏障通过特殊的指令来实现,这些指令确保了volatile
变量的读写操作满足内存语义。
Java中的内存屏障代码都在Unsafe
类中定义,共包含三个方法:LoadFence()
、StoreFence()
、FullFence()
。这些方法用于插入内存屏障,以保证内存操作的顺序性和可见性。
加分回答:
从内存语义的角度来看,volatile
的读/写与锁的获取/释放具有相同的内存效果。具体而言,volatile
的读与锁的获取具有相同的内存语义,volatile
的写与锁的释放具有相同的内存语义。
需要注意的是,volatile
只能保证单个变量的读/写的原子性,而锁(如synchronized
)可以保证对整个临界区的代码执行具有原子性。因此,在功能上锁比volatile
更强大,但在可伸缩性和性能上,volatile
通常更具优势。