当一个变量定义为volatile后,该变量对所有线程均可见。即当一条线程修改了这个变量的值,新值对于其他线程可以是立即得知的。但是这并不意味着volatile变量在并发下是线程安全的。这是因为volatile只保证当前线程在读取这个变量时,变量的值与其他所有线程一致。当前线程把读取到的一致的(在读的时候一致)值压入栈顶进行计算时,由于该计算可能不具备原子性。在执行该计算的各个字节码时,变量可能被其他线程改变。而这个改变并不会影响当前线程已压入栈顶的数据,这时栈顶的数据就成了过期的数据,从而发生线程安全问题。
所以,在不符合以下两条规则的运算场景中,我们仍然要通过加锁来保证原子性。
- 运算结果不依赖于变量的当前值,或者能够确保只有单一的线程修改变量的值
- 变量不需要与其他的状态变量共同参与不变约束
注:除了保持变量的可见性外,volatile关键字还有另一层语义:禁止指令重排序优化。
详见《深入理解java虚拟机》12.3.3节。