Java 廉价读写锁中的冗余易失性?
Brian Goetz在他的文章中 使用下面粘贴的示例作为廉价的读写锁。我的问题是,如果int变量值没有声明为volatile,那么它会有区别吗?我的理解是,由于对值的写入是在同步块内完成的,所以最新的值将以任何方式对其他线程可见,因此声明它为volatile是多余的。请澄清Java 廉价读写锁中的冗余易失性?,java,multithreading,concurrency,volatile,Java,Multithreading,Concurrency,Volatile,Brian Goetz在他的文章中 使用下面粘贴的示例作为廉价的读写锁。我的问题是,如果int变量值没有声明为volatile,那么它会有区别吗?我的理解是,由于对值的写入是在同步块内完成的,所以最新的值将以任何方式对其他线程可见,因此声明它为volatile是多余的。请澄清 @ThreadSafe public class CheesyCounter { // Employs the cheap read-write lock trick // All mutative operations
@ThreadSafe
public class CheesyCounter {
// Employs the cheap read-write lock trick
// All mutative operations MUST be done with the 'this' lock held
@GuardedBy("this") private volatile int value;
public int getValue() { return value; }
public synchronized int increment() {
return value++;
}
}
如果两个或多个线程试图同时递增,则此已同步
可防止您跳过递增(因为++
不是原子的)
这可以防止您在一个线程中看到过时的值,而该值在另一个线程中已经递增。(请注意,我们还可以使getValue同步以实现这一点)
我的理解是,由于对值的写入是在同步块内完成的,所以最新的值将以任何方式对其他线程可见
这是不正确的。通常,不能保证其他线程在变量发生更改后立即“看到”更改。线程可能会看到已更改变量的过时值,因为,例如,线程在寄存器而不是主内存中看到该值
一个volatile
变量建立了“before”语义。报告指出:
两个动作可以由“发生在之前”关系排序。如果一个动作发生在另一个动作之前,那么第一个动作对第二个动作可见并在第二个动作之前排序
- 对
易失性
字段(§8.3.1.4)的写入发生在该字段的每次后续读取之前
该字段必须是volatile的原因是,即使读取是原子的,它也需要确保该值是当前值,即之前由另一个线程写入的任何值都是可见的。读原子是不够的<代码>易失性仍然是确保值一致性所必需的。非常感谢各位的回答。现在在oracle网站上也发现了这一点:“第二,当同步方法退出时,它会自动与同一对象的同步方法的任何后续调用建立“发生在之前”关系。”
getValue
未同步。getValue()
可能会返回过时的值,因为它未同步,因此increment()
和getValue()
之间没有不带volatile
public synchronized int increment()
private volatile int value