为什么要用 volatile
- 某些程序判断逻辑的正确性依赖于程序执行语句的顺序。为了实现更好程序性能,Java编译器可能会通过改变内部指令的顺序来优化。当遇到多线程场景时,程序所依赖的语句执行顺序可能被破坏,进而导致逻辑判断出错
- 多线程环境中,部分线程可能会在某些时刻使用缓存在CPU寄存器中的副本数据,而不是直接从主内存获取(多核CPU中每个核心也可以有自己的缓存)。这会导致不同的线程使用了不同的数据,进而导致其它异常
volatile 的作用
通过用 volatile 修饰字段可以达到以下作用:
- volatile 会将对目标字段的读写操作直接指向主内存,而不是寄存器等缓存
- 这避免了前文第2点情况,保证其它线程都能读到最新的值
- 针对被volatile修饰的字段的读写操作不会被编译器“优化”
- 这避免了前文第1点情况,保证读写的顺序就是编码时规定的顺序。
- 如,如果代码中对某 volatile 修饰的字段的操作是先写再读,那么读操作可能会在写操作之后再执行
其它
- volatile 关键字可以用于类中的字段,但不能用于局部变量
- 局部变量是线程内部的数据,不是共享数据,所以volatile对其没有意义
- 对 volatile 修饰的 long 和 double 类型字段的读写也是原子性的
- 对 volatile 修饰字段的更改不需要互斥,所以volatile 关键字用得好,可以避免使用锁,提高性能
- 但 volatile 的目的并不是替代 synchronized