EJB design: solving lazy initialization and double checked locking problem
- Posted by: Vinay Aggarwal
- Posted on: November 29 2003 01:55 EST
I have suggested a solution for the lazy initialization avoiding double checked locking problem. The problem is explained here http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
My solution is posted here
One guy named Roger found a problem with it and it has been fixed in my next post.
I would like to know thoughts of people around here. Do you think this solution works?
- Effective Java by Sean Sullivan on November 29 2003 20:18 EST
- solving lazy initialization and double checked locking problem by Gal Binyamini on November 29 2003 20:50 EST
Read Josh Bloch's "Effective Java"
I don't see how either of your versions prevent the following problem:
Thread1 calls lazyInit.getHeavyObject(). Everything goes well, the heavyObject and heavyObjectInit fields are updated, and the heavyObject instance and it's fields are properly flushed from Thread1's working copy to the main memory.
Now Thread2 comes in. It uses the updated heavyObjectInit to read heavyObject. At no point in this sequence did Thread2 perform a monitorenter operation. Therefore it is not required to refresh it's working copy. The fields of the heavyObject instance are read from the working copy as their default values and any changes made by HeavyObject's constructor are not observed by Thread2. This is obviously an error. Remember that volatile fields are only required to be totally ordered with respect to other volatile fields. Non-volatile fields (such as fields updated by the HeavyObject constructor) can still be seen out of order.
There might also be a problem of a prescient-stroe in line 14. I didn't understand if you think the addition of i should fix this problem.
A precient store is a situation where a thread stores a value in main memory before the value is assigned by the thread (i.e., before the thread reached the assignment instruction). It is allowed when:
1. the variable isn't volatile.
2. if the store occurs, the assign is bound to occur.
3. no lock operation or another store/load of the variable are performed between the store and the matching assign.
4. the value written to the memory by store is the same as the value that would be assigned by the thread.
(see VM spec section 8.8)
In practice it is unlikely that the compiler be able to use a precient store in this situation. Intuitively if condition on i (i>0) should make it hard for the compiler to make sure condition 2 is met. However none of the conditions above are strictly violated.
The precient-store situation is very rare in this context anyway. How can the compiler know that the creation of HeavyObject won't exhaust the memory and result in an OutOfMemoryError, and thus prevent the assign operaion from occuring (in violation of rule 2 avole)?
However, the first problem I mentioned can actually occur in some multiprocessor architectures (this is explained in Doug Pugh's page you linked to).