7

I have a class Item

class Item {
  public int count;
  public Item(int count) {
    this.count = count;
  }
}

Then, I will put a reference to Item in a field of other class

class Holder {
  public Item item;
  public Holder() {
    item = new Item(50);
  }
}

Can this new Item object be safely published? If not, why? According to Java Concurrency in Practice, the new Item is published without being fully constructed, but in my opinion the new Item is fully constructed: its this reference doesn't escape and the reference to it and its state is published at the same time, so the consumer thread will not see a stale value. Or is it the visibility problem. I don't exactly know the reason.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
ohyeahchenzai
  • 314
  • 3
  • 13

2 Answers2

16

Can this new Item object be safely published? If not, why?

The issue revolves around optimizations and reordering of instructions. When you have two threads that are using a constructed object without synchronization, it may happen that the compiler decides to reorder instructions for efficiency sake and allocate the memory space for an object and store its reference in the item field before it finishes with the constructor and the field initialization. Or it can reorder the memory synchronization so that other threads perceive it that way.

If you mark the item field as final then the constructor is guaranteed to finish initialization of that field as part of the constructor. Otherwise you will have to synchronize on a lock before using it. This is part of the Java language definition.

Here's another couple references:

Gray
  • 115,027
  • 24
  • 293
  • 354
  • Maybe I should read the java language specification , thank you! – ohyeahchenzai Apr 24 '12 at 15:43
  • Let me point you straight to the correct [chapter.](http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4) It's a great read, much more than just dry specification. – Marko Topolnik Apr 24 '12 at 15:46
  • Thanks @Marko. I've added that link into my answer. – Gray Apr 24 '12 at 15:47
  • For such a high-score answer: *JVM decides to reorder instructions for efficiency sake and allocate the memory space for an object and store its reference in the item field before it finishes with the constructor and the field initialization.* - this does not happen b/c the c-tor can throw an exception - hence in no shape or form the reference CAN be stored to speak before the c-tor finishes. While due to OOO and cache coherency (that's hardware level) the reference to the object state can be "made" visible to other threads prior to the fields (object state) – bestsss Jul 02 '12 at 12:01
  • I'm not sure I understand the comment but as I read it @bestsss, that is not my understanding. The whole reason why double check locking is broken is because the constructor might finish, the reference stored, but the fields have not been initialized either in reality or because of memory syncing. See the following copy and associated link "writes that initialize the Helper object and the write to the helper field can be done or perceived out of order": http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html – Gray Jul 02 '12 at 13:34
  • out of order is on the hardware level (on weak memory model). I know no JVM that initializes the references (CPU instruction) before it has actually finished, probably I need more space to illustrate but imagine: if the c-tor throws an exception and the reference was initialized before the c-tor finished, in the catch block one can clearly see the reference initialized. That's for the same thread. When more CPUs are involved and out-of-order execution/memory model that stuff goes hairy and ends up w/ the famous paper on the double-locking. Point is: it isn't the JVM that reorders the writes. – bestsss Jul 02 '12 at 13:52
  • reordering does happen but it's b/c of cache coherency not b/c JVM actually reorders the writes to the fields with the write to the reference of the object. It's true it's done b/c of performance, it's just not the JVM that does it. – bestsss Jul 02 '12 at 13:54
  • Doug Lea's memory model page disagrees with this. It uses the word compiler instead of JVM but it is definitely at the software level and not just about hardware pipelining and cache coherency: http://gee.cs.oswego.edu/dl/cpj/jmm.html – Gray Jul 02 '12 at 13:57
  • I understand your exception point and I don't know how that fits into the puzzle. Maybe the compiler does just enough to ensure that the ctor will not throw but then is not guaranteed to do the rest. Again, we are talking about the memory model an guarantees. – Gray Jul 02 '12 at 13:59
  • btw, really nice to keep the references handy :) I also mean the compiler. Of course, in theory the JVM/compiler can reorder the writes to the reference and the fields but in practice it's not done. Again my point is that compiler/JVM doesn't reorder the write to the reference w/ the object initialization for performance reasons. Proving no exception occurs would require (probably) only direct writes to fields and no loads/method invocations, no safe points generated. – bestsss Jul 02 '12 at 14:12
  • Please show me data that it is "not done". That's a very dangerous assumption I believe. – Gray Jul 02 '12 at 14:30
  • so making a field final guarantees atomic initialization? – amarnath harish Apr 13 '18 at 18:06
  • Not atomic but it guarantees that the field will be properly initialized before the constructor finishes @amarnathharish. – Gray Apr 13 '18 at 21:15
6

Yes, there is a visibility problem, as Holder.item is not final. So there is no guarantee that another thread will see its initialized value after the construction of Holder is finished.

And as @Gray pointed out, the JVM is free to reorder instructions in the absence of memory barriers (which can be created by a lock (synchronization), a final or volatile qualifier). Depending on the context, you must use one of these here to ensure safe publication.

Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • I think I may get the answer ,it is the reorder , but I don't the exactly order it may take ,but as Gray pointed it out , I know some about it , thank you both! – ohyeahchenzai Apr 24 '12 at 15:48
  • @ohyeahchenzai If you carefully study the chapter if JLS mentioned in the other answer, it will all be clear to you. – Marko Topolnik Apr 24 '12 at 15:49
  • Yet another good reason to favor immutability by making the fields final. – Steve Kuo Apr 24 '12 at 15:50
  • @SteveKuo, indeed, if it is acceptable to the OP, `final` is the best solution. But since we don't know anything about the intended usage of the field, I listed the other options too. – Péter Török Apr 24 '12 at 19:02
  • @PéterTörök,I haven't read the JLS , I read the Think In Java first , and then I think I should deep in some field , so I choose the JCIP , but I wasn't that clear with Java Memory Model , so I met some questions like this one ,thanks for your advice.^_^ – ohyeahchenzai Apr 25 '12 at 13:39