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