简体   繁体   中英

Does Java volatile variables impose a happens-before relationship before it is read?

I have a piece of code which looks like this:

Snippet A:

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

From my understanding, since reading of numCreated is not synchronized, if Thread-A creates a Creature at 1pm, and Thread-B reads numCreated() at 2pm, numCreated() may well have returned either 0 or 1 (even when Thread-A has finished initializing the object at 1.05pm).

So I added synchronized to numCreated() :

Snippet B :

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

and all's well, except that I was thinking, if I modify it to Snippet C , is the variable numCreated still synchronized properly?

Snippet C:

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

With Snippet C , is it guaranteed that as soon as Thread-A completes object creation at 1:05pm, Thread-B's call to numCreated() is sure to return 1 ?

PS: I understand that in a real situation I would probably use an AtomicLong but this is for learning purposes

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

A write to a volatile field happens-before every subsequent read of that same field. Writes and reads of volatile fields have similar memory consistency effects as entering and exiting monitors, but do not entail mutual exclusion locking.

So the answer is yes. The write of the volatile in the constructor happens before the read of the volatile in numCreated() . And since the non-atomic incrementation is still done in a synchronized block, the synchronization is alright (the incrementation is not atomic, but the write of the volatile long is).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM