volatile 两大特性
- 禁止重排序
- 内存可见性
volatile 修饰的变量和普通变量的区别
- 对于 volatile 变量:读操作时 JMM 会把工作内存中对应的值设为无效,要求线程从主内存中读取数据;写操作时 JMM 会把工作内存中对应的数据刷新到主内存中。这种情况下,其它线程就可以读取变量的最新值。
- 对于普通变量:读操作会优先读取工作内存的数据,如果工作内存中不存在,则从主内存中拷贝一份数据到工作内存中;写操作只会修改工作内存的副本数据。这种情况下,其它线程就无法读取变量的最新值。
所谓的内存可见性就是指:对于 volatile 修饰的变量,JVM 虚拟机保证从主内存加载到线程工作内存的值是最新的
ps:JMM(Java Memory Model):Java 内存模型
volatile 和 synchronized 的区别
出处见这里:
- volatile 是告诉 JVM 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取
synchronized 则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞 - volatile 仅能使用在变量级别
synchronized 可以直接使用在方法、代码块级别,间接用于变量和类级别 - volatile 仅能实现变量的可见性,不能保证原子性 synchronized 则可以保证变量的可见性和原子性
- volatile 不会造成线程阻塞 synchronized 可能会造成线程的阻塞
- volatile 标记的变量不会被编译器重排序 synchronized 标记的变量可以被编译器重排序
volatile 的应用场景
volatile 的应用场景需要满足两个条件:
- 对变量的写操作不依赖当前值
- 该变量没有包含在具有其它变量的不变式中
最常见的莫过于单例的双重检查加锁,详情见这里