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

Pac*_*ier 8 java concurrency multithreading

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

片段A:

class Creature {
    private static long numCreated;
    public Creature() {
        synchronized (Creature.class) {
            numCreated++;
        }
    }
    public static long numCreated() {
        return numCreated;
    }
}
Run Code Online (Sandbox Code Playgroud)

根据我的理解,由于读取numCreated不同步,如果Thread-A Creature在下午1点创建一个,并且Thread-B numCreated()在下午2点读取,则numCreated()可能返回0或1(即使Thread-A已在1.05pm完成初始化对象) ).

所以我添加synchronizednumCreated():

代码片段B:

class Creature {
    private static long numCreated;
    public Creature() {
        synchronized (Creature.class) {
            numCreated++;
        }
    }
    public static synchronized long numCreated() { // add "synchronized"
        return numCreated;
    }
}
Run Code Online (Sandbox Code Playgroud)

并且一切都很好,除了我在想,如果我将它修改为Snippet C,变量是否numCreated仍然正确同步?

片段C:

class Creature {
    private static volatile long numCreated; // add "volatile"
    public Creature() {
        synchronized (Creature.class) {
            numCreated++;
        }
    }
    public static long numCreated() { // remove "synchronized"
        return numCreated;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用Snippet C,可以保证一旦Thread-A在下午1:05完成对象创建,Thread-B的调用numCreated()肯定会返回1吗?

PS:我知道在实际情况下我可能会使用,AtomicLong但这是出于学习目的

JB *_*zet 6

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

在每次后续读取同一字段之前,会发生对易失性字段的写入.易失性字段的写入和读取具有与进入和退出监视器类似的内存一致性效果,但不需要互斥锁定.

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