I am trying to simply test out the initialization safety of final fields as guaranteed by the JLS. It is for a paper I'm writing. However, I am unable to get it to 'fail' based on my current code. Can someone tell me what I'm doing wrong, or if this is just something I have to run over and over again and then see a failure with some unlucky timing?
Here is my code:
public class TestClass { final int x; int y; static TestClass f; public TestClass() { x = 3; y = 4; } static void writer() { TestClass.f = new TestClass(); } static void reader() { if (TestClass.f != null) { int i = TestClass.f.x; // guaranteed to see 3 int j = TestClass.f.y; // could see 0 System.out.println("i = " + i); System.out.println("j = " + j); } } }
and my threads are calling it like this:
public class TestClient { public static void main(String[] args) { for (int i = 0; i < 10000; i++) { Thread writer = new Thread(new Runnable() { @Override public void run() { TestClass.writer(); } }); writer.start(); } for (int i = 0; i < 10000; i++) { Thread reader = new Thread(new Runnable() { @Override public void run() { TestClass.reader(); } }); reader.start(); } } }
I have run this scenario many, many times. My current loops are spawning 10,000 threads, but I've done with this 1000, 100000, and even a million. Still no failure. I always see 3 and 4 for both values. How can I get this to fail?
Note that any final field must be initialized before the constructor completes. For static final fields, this means that we can initialize them: upon declaration as shown in the above example. in the static initializer block.
Within a default constructor.
1) Immutable objects are by default thread-safe because their state can not be modified once created. Since String is immutable in Java, it's inherently thread-safe. 2) Read-only or final variables in Java are also thread-safe in Java.
When should I use final? One answer to this is "whenever you possibly can". Any field that you never expect to be changed (be that a primitive value, or a reference to an object, whether or not that particular object is itself immutable or not), should generally be declared final.
I wrote the spec. The TL; DR version of this answer is that just because it may see 0 for y, that doesn't mean it is guaranteed to see 0 for y.
In this case, the final field spec guarantees that you will see 3 for x, as you point out. Think of the writer thread as having 4 instructions:
r1 = <create a new TestClass instance> r1.x = 3; r1.y = 4; f = r1;
The reason you might not see 3 for x is if the compiler reordered this code:
r1 = <create a new TestClass instance> f = r1; r1.x = 3; r1.y = 4;
The way the guarantee for final fields is usually implemented in practice is to ensure that the constructor finishes before any subsequent program actions take place. Imagine someone erected a big barrier between r1.y = 4 and f = r1. So, in practice, if you have any final fields for an object, you are likely to get visibility for all of them.
Now, in theory, someone could write a compiler that isn't implemented that way. In fact, many people have often talked about testing code by writing the most malicious compiler possible. This is particularly common among the C++ people, who have lots and lots of undefined corners of their language that can lead to terrible bugs.
From Java 5.0, you are guarenteed that all threads will see the final state set by the constructor.
If you want to see this fail, you could try an older JVM like 1.3.
I wouldn't print out every test, I would only print out the failures. You could get one failure in a million but miss it. But if you only print failures, they should be easy to spot.
A simpler way to see this fail is to add to the writer.
f.y = 5;
and test for
int y = TestClass.f.y; // could see 0, 4 or 5 if (y != 5) System.out.println("y = " + y);
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