I'm reading a book "Java concurrency in practice" by Brian Goetz. Paragraphs 3.5 and 3.5.1 contains statements that I can not understand.
Consider the following code:
public class Holder {
private int value;
public Holder(int value) {
this.value = value;
}
public void assertValue() {
if (value != value) throw new AssertionError("Magic");
}
}
class HolderContainer {
// Unsafe publication
public Holder holder;
public void init() {
holder = new Holder(42);
}
}
Author states that:
- In Java, Object constructor first writes default values to all fields before subclass constructor run.
- Therefore it's possible to see field default value as a stale value.
- Thread may see stale value the first time it reads a field and then a more up-to-date value the next time, which is why assertN can throw AssertionError.
So, according to the text, with some unlucky timing it is possible that value = 0; and in the next moment value = 42.
I agree with point 1 that Object constructor firstly fills fields with default values. But I don't understand points 2 & 3.
Let's update authors code and consider the following example:
public class Holder {
int value;
public Holder(int value) {
//Sleep to prevent constructor to finish too early
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.value = value;
}
public void assertValue() {
if(value != value) System.out.println("Magic");
}
}
I've added Thread.sleep(3000), to force thread to wait before object will be fully constructed.
public class Tests {
private HolderContainer hc = new HolderContainer();
class Initialization implements Runnable {
public void run() {
hc.init();
}
}
class Checking implements Runnable {
public void run() {
hc.holder.assertValue();
}
}
public void run() {
new Thread(new Initialization()).start();
new Thread(new Checking()).start();
}
}
In example:
- first thread inits holder object
- second thread calls assertValue
Main Thread runs two threads:
- new Thread(new Initialization()).start(); It tooks 3 seconds to fully construct Holder object
- new Thread(new Checking()).start(); since Holder object still not constructed code will throw an NullPointerException
Therefore, it's impossible to emulate situation when field has default value.
My Questions:
- Author was wrong about this concurrency problem?
- Or It it impossible to emulate behaviour for fields default values?
Did not reproduce it with your code. Here is an example to emulate un-safe publication. The strategy is let one thread publication
Holder
and let another check its value.I tried to test the problem with the following code.
Test:
Holder:
I never got the program to evaluate
value!=value
totrue
. I don't think this proves anything and didn't run it for more than a couple minutes, but I hope this will be a better starting point for a well designed test or at least help to figure out some possible flaws in the tests.I tried to insert a sleep between
Test.hc=new HolderContainer();
andTest.hc.init();
, betweenpublic Holder holder;
andpublic void init() {
and afterpublic void init() {
.I am also concerned that checking if a value is
null
or catching theNullPoiterException
may affect the timing too much.Please note that the currently accepted answer to Improper publication of Java Object Reference says this problem is probably impossible under an x86 architecture. It may also be JVM dependent.
You are probably trying to simulate a concurrency scenario, which I believe is very hard to simulate using a couple of threads.
The following test-case which you have written is not correct at all is more likely to throw a
NullPointerException.
What if your Checking Thread executes before Initialization one?? Also putting a sleep there simply means that executing thread will sleep and does tell you about the internal atomic operations being performed by then.