There are two questions you ask:
1. Can the getInstance() method return null due to reordering?
(which I think you really are after this, so I will try to answer it first)
Although I believe that creating Java for this is absolutely insane, it seems like you actually right that getInstance() can return null.
Code example:
if (resource == null) resource = new Resource(); // unsafe publication return resource;
logically 100% identical to the blog example you linked to:
if (hash == 0) { // calculate local variable h to be non-zero hash = h; } return hash;
Jeremy Manson then describes that his code may return 0 due to reordering. Firstly, I did not believe in this, because I thought the following “happen-to” -logical should be done:
"if (resource == null)" happens before "resource = new Resource();" and "resource = new Resource();" happens before "return resource;" therefore "if (resource == null)" happens before "return resource;", preventing null
But Jeremy cites the following example in a comment on his blog post, how this code can be correctly rewritten by the compiler:
read = resource; if (resource==null) read = resource = new Resource(); return read;
This in a single-threaded environment behaves exactly the same as the source code, but in a multi-threaded environment it can lead to the following execution order:
Thread 1 Thread 2 ------------------------------- ------------------------------------------------- read = resource; // null read = resource; // null if (resource==null) // true read = resource = new Resource(); // non-null return read; // non-null if (resource==null) // FALSE!!! return read; // NULL!!!
Now, from an optimization point of view, it makes no sense to me, since the whole point of these things would be to reduce several readings in one place, and in this case there is no point in the fact that the compiler does not generate if (read==null) , preventing the problem. So, as Jeremy points out on his blog, this is unlikely to happen. But it seems that, purely from the point of view of the rules of the language, in fact, this is allowed.
This example is really covered in JLS:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4
The effect observed between r2 , r4 and r5 in Table 17.4. Surprising results caused by forward substitution Table 17.4. Surprising results caused by forward substitution is equivalent to what can happen with read = resource , if (resource==null) and return resource in the example above.
Also: why am I referring to a blog post as the ultimate source of response? Because the guy who wrote this is also the guy who wrote JLS chapter 17 on concurrency! So it’s better to be right! :)
2. Would make the Resource immutable to make the getInstance() method thread safe?
Given the potential null result that can occur regardless of whether the Resource volatile or not, the immediate simple answer to this question is: No (not strictly)
If we ignore this extremely unlikely, but possible scenario, the answer is: Depends .
The obvious problem with the code stream is that it can lead to the following execution order (without any reordering):
Thread 1 Thread 2 ---------------------------------------- ---------------------------------------- if (resource==null) // true; if (resource==null) // true resource=new Resource(); // object 1 return resource; // object 1 resource=new Resource(); // object 2 return resource; // object 2
Thus, non-thread safety comes from the fact that you can return two different objects from a function (although without reordering, none of them will ever be null ).
Now what the book was probably trying to say is this:
Immutable Java objects, such as strings and integers, try not to create multiple objects for the same content. So, if you have "hello" in one place and "hello" in another place, Java will provide you with the exact same description of the object. Similarly, if you have new Integer(5) in one place and new Integer(5) in another. If this were the case with new Resource() , you would get the same link back, and object 1 and object 2 in the above example would be the same object. This would indeed lead to an efficient thread-safe function (ignoring the reordering problem).
But if you implement Resource yourself, I do not believe that there is even a way for the constructor to return a link to a previously created object, rather than creating a new one. Thus, you cannot make object 1 and object 2 the same object. But, given that you are calling the constructor with the same arguments (neither in both cases), it is likely that although your created objects are not the same exact object, they will, in effect, behave as if they were also effectively make code safe for threads.
This does not have to be so. Imagine an immutable version of Date , for example. The default constructor, Date() uses the current system time as the date value. Thus, although the object is immutable and the constructor is called with the same argument, calling it twice probably will not result in an equivalent object. Therefore, the getInstance() method is not thread safe.
So, as a general statement, I believe that the line you quoted from the book is simply incorrect (at least as inferred from the context here).
ADD Re: reordering
I find the resource==new Resource() example too simplistic to help understand why WHY allows such Java reordering to ever make sense. So let me see if I can come up with something that could help in the optimization:
System.out.println("Found contact:"); System.out.println(firstname + " " + lastname); if (firstname==null) firstname = ""; if (lastname ==null) lastname = ""; return firstname + " " + lastname;
, , ifs false , String firstname + " " + lastname , , . , , :
System.out.println("Found contact:"); String contact = firstname + " " + lastname; System.out.println(contact); if ((firstname==null) || (lastname==null)) { if (firstname==null) firstname = ""; if (lastname ==null) lastname = ""; contact = firstname + " " + lastname; } return contact;
, , , / , , , . , , - , , , , , , / , , . , , , , , , ( , ).
, , , .