Java volatile变量是否会在读取之前强制执行之前的关系?

时间:2011-11-05 22:22:04

标签: java multithreading concurrency

我有一段看起来像这样的代码:

Snippet A:

class Creature {
    private static long numCreated;
    public Creature() {
        synchronized (Creature.class) {
            numCreated++;
        }
    }
    public static long numCreated() {
        return numCreated;
    }
}

根据我的理解,由于numCreated的读取未同步,如果Thread-A在下午1点创建Creature,而Thread-B在下午2点创建numCreated(),{{1}可能已经返回0或1(即使Thread-A在晚上1点05分完成对象的初始化)。

所以我将numCreated()添加到synchronized

Snippet B

numCreated()

并且一切都很好,除了我在想,如果我将其修改为 Snippet C ,变量class Creature { private static long numCreated; public Creature() { synchronized (Creature.class) { numCreated++; } } public static synchronized long numCreated() { // add "synchronized" return numCreated; } } 是否仍然正确同步?

Snippet C:

numCreated

使用 Snippet C ,可以保证一旦Thread-A在下午1:05完成对象创建,Thread-B对class Creature { private static volatile long numCreated; // add "volatile" public Creature() { synchronized (Creature.class) { numCreated++; } } public static long numCreated() { // remove "synchronized" return numCreated; } } 的调用肯定会返回{{1} }?

PS:据我所知,在实际情况下,我可能会使用numCreated(),但这是出于学习目的

1 个答案:

答案 0 :(得分:6)

请参阅http://download.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility

  

在每次后续读取之前发生对易失性字段的写入   那个领域。易失性字段的写入和读取具有相似之处   进入和退出监视器时的内存一致性效果,但确实如此   不需要互斥锁定。

所以答案是肯定的。构造函数中volatile的写入发生在numCreated()中读取volatile之前。并且由于非原子增量仍然在同步块中完成,因此同步是正常的(增量不是原子的,但写入volatile的长度是)。