Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 522
Pacerier Avatar asked Nov 05 '11 22:11

Pacerier


People also ask

What happens when a volatile variable is declared in Java programming?

By declaring the counter variable volatile all writes to the counter variable will be written back to main memory immediately. Also, all reads of the counter variable will be read directly from main memory. Declaring a variable volatile thus guarantees the visibility for other threads of writes to that variable.

What happens when a variable is declared as volatile?

Volatile is a qualifier that is applied to a variable when it is declared. It tells the compiler that the value of the variable may change at any time-without any action being taken by the code the compiler finds nearby.

How does the volatile keyword affect how a variable is handled?

The volatile keyword does not cache the value of the variable and always read the variable from the main memory. The volatile keyword cannot be used with classes or methods. However, it is used with variables. It also guarantees visibility and ordering.

How does Java implement volatile?

A volatile keyword is used to modify the value of a variable by different threads. It is also used to make classes thread-safe. It means that multiple threads can use a method and instance of the classes at the same time without any problem. The volatile keyword can be used either with primitive type or objects.


1 Answers

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).

like image 200
JB Nizet Avatar answered Nov 06 '22 12:11

JB Nizet