3 ms·
a couple of examples in RA mode involving constructors and final fields look unnecessary to me. I thought the java memory model already guaranteed a release/acq
by sreque 10y ago
a couple of examples in RA mode involving constructors and final fields look unnecessary to me. I thought the java memory model already guaranteed a release/acquire fence at the end of constructor for final fields. Basically if a thread sees an object post-construction, it is already guaranteed to see the correct values for the object's final fields. Am I mistaken here?
- mnw21cam 10y agoIndeed. It is possible to see an object half-way through construction if you are viewing it unsynchronised from a different thread to the thread constructing it. This is why the common pattern of double-checked locking is bad. This is: class Thing { private Thing thing = null; public Thing getThing() { if (thing == null) { synchronized (this) { if (thing == null) { thing = new Thing(); } } } return thing; } } Don't do that. You could get hold of a partially-constructed Thing.
- sreque 10y agoIt's actually not possible to get a hold of partially-constructed thing in this manner, assuming the thing only has final variables. See http://g.oswego.edu/dl/jmm/cookbook.html http://g.oswego.edu/dl/jmm/cookbook.html. "The initial load (i.e., the very first encounter by a thread) of a final field cannot be reordered with the initial load of the reference to the object containing the final field. This comes into play in: x = sharedRef; ... ; i = x.finalField; A compiler would never reorder these since they are dependent, but there can be consequences of this rule on some processors." Note that there are no constraints placed on sharedRef. It does not need to be volatile, for instance. This link also has more useful info and examples: https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#finalRight https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.ht...
- chrisseaton 10y ago> there can be consequences of this rule on some processors Right - I think the processor can still reorder. I've never been sure why the compiler is not allowed to reorder in this case, since this doesn't help you if the processor will do it anyway.
- sreque 10y agoThe "consequences on some processors" simply means that a conforming java compiler/VM may need to insert memory barriers to enforce the memory model for constructors, resulting in a performance penalty. A conforming compiler or VM cannot generate code that would allow processor re-orderings to break the memory model.
- deleted 10y ago[deleted]
- xxs 10y agoIn such a case the compiler has to insert a store-store barrier and not reorder the instructions to conform to JMM.
- deleted 10y ago[deleted]
- hinkley 10y agoGP just has old information. Prior to widespread adoption of JSR-133, at which point Java was over 10 years old, things were demonstrably broken if you got clever with concurrency.
- deleted 10y ago[deleted]
- bad_user 10y agoScala's "lazy val" is using the double-checked locking pattern and I've never experienced problems with it (except for synchronizing on "this", but that's another issue). In the example you're mentioning if "Thing" is built with finals or if it is synchronized, then it can't have problems. And given that "Thing" in this sample is meant to be accessed by multiple threads, then if that access isn't synchronized, then the double-checked pattern is not going to be your only problem ;-)
- _old_dude_ 10y agoScala's lazy val uses the double-checked locking pattern with the field declared volatile, (the private field thing in the example) that's why there is no issue
- bad_user 10y agoIt doesn't matter if the field is volatile, it won't protect you in this case. Basically when assigning a new object to a reference, the only way to know for sure that its internals are initialized before the assignment is to either work with finals or to synchronize that internal state.
- _old_dude_ 10y agoif the field is volatile, you have an happen before relationship between the volatile read of thing before the synchronized block and the volatile write inside the synchronized block, so you have no way to see the object partially initialized. It only works with the updated semantics of volatile (Java 5+), otherwise you're right.
- xxs 10y agoAt the very least Thing should be volatile. Technically, you do need a local variable, too.
- sgolestane 10y agoI think you missed the 'final' keyword from @sreque comment. As long as at least one of the fields of the Thing is final, instances of it get published safely (https://shipilev.net/blog/2014/safe-public-construction/ https://shipilev.net/blog/2014/safe-public-construction/)
- MichaelGG 10y agoI've heard this in C# too, but it seems to me if you can get partially constructed objects, you might be able to leverage that into a sandbox/(.net "code access security") exploit. Or violate code assumptions (say the object provides a method that does something unsafe if the object isn't initialized -- it'd be impossible to write such an object safely, if calling code can partially initialize it, right?).