Compiler writers (static and runtime) will make optimisations based on the JMM whether it's acceptable to us or not, these optimisations can change between releases, so something that works ok most of the time now during testing, may not work at all in future ,or fail under load.
JSR133, the java memory model (JMM), is a contract between programmers and compiler writers, it guarantees predictable behaviour for programmers that follow the rules laid out by the JMM. Section 3.2 Final fields, paragraph 4 states: "The usage model for final fields is a simple one. Set the final fields for an object in that object's constructor. Do not write a reference to an object being constructed in a place where another thread can see it before the object's constructor is finished." I think the JMM is a standard we should consider adopting, to improve the predictability and stability of our code across different java platforms and releases. I had three choices for creating services that contained final fields in a manner compliant with the JMM: 1. Add a Starter interface with a start method. 2. Use inheritance, where final fields belong in a superclass, and a stateless child class exports and starts any threads. 3. Disallow final fields. Which method would you choose and why? ----- Original message ----- > > On Dec 20, 2013, at 2:49 PM, Dan Creswell <dan.cresw...@gmail.com> wrote: > > > > BUT > > > > The critical aspect is not releasing the reference to an object to > > another thread before construction completes but that other thread > > READING that final variable using that reference before construction > > is complete. > > > > i.e. there is nothing wrong with releasing a reference, it's about > > what you do with it and when. > > Okay, this is where it’s important to make sure that everyone is getting > what the JMM says. This is not about “when” but the “order”. If we > have the tasks identified as follows: > > 1. T1 starts to construct O1 > 2. T2 gains reference to O1 via T1 handing it a reference > 3. T1 completes construction of O1 > 4. T2 reads some value from the fields of O1 > > then one could say that the constructor completed before the reference > to O1, by T2. What I think is important to understand, is that you > have to guarantee that will happen with a shared happens before > relationship between T1 and T2. > > Theory based programming is used to make sure this happens. Test base > programming might result in some delay being placed in T2 such that T1 > should always complete. > > I don’t think that there is anyone here that would do such a thing, but > sometimes it happens by mistake. I.e. what if T2 goes to do something > on the network in the test, accessing a nonexistent DNS server which > stalls it and causes the timing to work out okay? What if the 3.5 > second reduction to 2 second reduction that Peter made, opens the window > to T2 using O1 before T1 completes? > > We really do need to fix these things. I’ve made many, many patches to > my private copy of Jini over the years, specifically related to seeing > these kinds of things going on. It’s real stuff. As I’ve said before. > Many of us are being saved by the fences and locks in Vector and > Hashtable which are causing implicit happens-before events which fix > these issues. But, those structures just KILL performance. As we > remove the use of those, as Patricia said, other things are going to > start breaking, and Peter has found that happening all along his path of > exploration of how bad things actually are. > > Gregg Wonderly