I have this simple piece of code.
class A {
static volatile String[] a = new String[9];
public static void main(String[] args) {
new Thread() {
public void run() {
for (int i = 0; i < a.length; i++) {
while (a[i] == null);
System.out.println(a[i]);
}
}
}.start();
a[0] = "The";
zzz();
a[1] = "quick";
zzz();
a[2] = "brown";
zzz();
a[3] = "fox";
zzz();
a[4] = "jumped";
zzz();
a[5] = "over";
zzz();
a[6] = "the";
zzz();
a[7] = "lazy";
zzz();
a[8] = "cat";
zzz();
}
public static void zzz() {
try {
Thread.sleep(300);
} catch (Exception e) {}
a=a;
}
}
It outputs what I'd expect:
$ javac A.java && java A
The
quick
brown
fox
jumped
over
the
lazy
cat
The strange thing is the a=a
in zzz()
. It doesn't seem to change anything when I take it out. Why is it there?
The only reason I can think of is that the person who wrote that code understood that only the array is volatile but not its content and added a = a
to enforce visibility of the writes performed on the array items.
It doesn't seem to change anything when I take it out.
The fact that it still works on your machine with your JVM does not mean that it would work on another machine with a different JVM. In theory, removing the a = a;
statement could lead to a never-ending while loop.
Side note
I would have thought that the Java Memory Model (JMM) could allow a JVM to ignore that statement, the same way that a synchronized(new Object())
can be ignored.
It seems however that it is not the case*:
You may have noticed that I did provide a way of getting a volatile write above with just arrays: by writing out a self-reference.
*Jeremy Manson is one of the authors of the JMM.