线程在无同步情况下读取变量时,可能会得到一个失效值,但该值并非随机值,而是此前某个线程设置的值。该策略被称为“最低安全性”。
最低安全性策略适用于几乎所有变量,但是对非 volatile 类型的64位变量值(double,long)不生效。因为 Java 内存模型要求变量的读取与写入操作必须是原子操作,但对于非 volatile 的 long 和 double , JVM 允许将64位的读写操作分解为两个32位操作。也就是读取非 volatile 的 long 变量时,如果读和写在不同线程中执行,可能出现读取到某值的高32位以及另一个值的低32位。因此对于该类型的变量,必须用 volatile 声明或者使用锁进行保护。
同步锁的作用不仅在于线程间执行代码块互斥,还能保证所有线程能够得到共享变量的最新值,不会出现因为不确定的语句执行顺序导致获取过期的变量值。前提是所有线程必须在同一个锁上同步。
与加锁机制相比,volatile 只能保证可见性而不能保证原子性。而且使用 volatile 的约束条件比较严格:
volatile 约束规则 | |
---|---|
变量的写入操作不依赖变量当前值,或者能够确保只有单个线程更新变量值 | |
访问变量时不需要加锁 | |
变量不会被纳入不变性条件 |
只有同时满足以上三点,才能使用 volatile