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:
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:
Main Thread runs two threads:
Therefore, it's impossible to emulate situation when field has default value.
My Questions:
I tried to test the problem with the following code.
Test:
public class Test {
public static boolean flag =true;
public static HolderContainer hc=new HolderContainer();
public static void main (String args[]){
new Thread(new Initialization()).start();
new Thread(new Checking()).start();
}
}
class Initialization implements Runnable {
public void run() {
while (Test.flag){
Test.hc=new HolderContainer();
Test.hc.init();
}
}
}
class Checking implements Runnable {
public void run() {
try{
Test.hc.holder.assertValue();
}
catch (NullPointerException e) {
}
}
}
Holder:
public class Holder {
private int value;
public Holder(int value) {
this.value = value;
}
public void assertValue() {
if (value != value) {
System.out.println("Magic");
Test.flag=false;
}
}
}
class HolderContainer {
public Holder holder;
public void init() {
holder = new Holder(42);
}
}
I never got the program to evaluate value!=value
to true
.
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();
and Test.hc.init();
, between public Holder holder;
and public void init() {
and after public void init() {
.
I am also concerned that checking if a value is null
or catching the NullPoiterException
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With