• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Ron McLeod
  • paul wheaton
  • Jeanne Boyarsky
Sheriffs:
  • Paul Clapham
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
  • Himai Minh
Bartenders:

multi processor and double checked locking

 
Ranch Hand
Posts: 50
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


I was reading this thread about why double checked locking fails in a multi-processor environment.

http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-toolbox.html?page=4

In the page 3, the author mentions that -

"To summarize, synchronization implies a memory barrier. Consequently, though the code within the synchronized block is subject to reordering, all modifications made within that block will be visible in main memory (for other threads to view) when you exit the synchronized block."

and in page 4 -

"The problem: the assignments that occur within the constructor occur within the same memory barrier as the assignment to the_instance. As a consequence, it's possible for the_instance to be non-null, even though the assignments that occurred in the constructor are yet not visible. If one thread gets as far as the statement the_instance=new Disfunctional_singleton(), and the assignment to the_instance is visible but the assignments within the constructor are not yet visible, then a second thread that calls get_instance() method can return a pointer to an uninitialized object. "

That seems contradictory because once you exit the synchronized block everything should be visible.

Does that mean that a thread can exit by just issuing a call to the constructor even before the construction is complete?

Thanks.
 
Bartender
Posts: 15741
368
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Suma. You can disregard that article. It was written in 2001, and Java's memory model was greatly modified in 2004.
 
Ranch Hand
Posts: 134
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

thanks
 
Suma Rangaraj
Ranch Hand
Posts: 50
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
1) so what is the real issue with double checked locking on single vs multi-processor CPUs? How is the new memory model different?

2) if a thread 1 is executing a synchronized block and Thread 2 preempts thread 1, does it mean thread 1 will have to forcibly exit the synchronized block in between?


I will really appreciate if some one can answer my questions - there is just too much information in the internet is confusing.

Thanks.
 
Ranch Hand
Posts: 443
3
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
- The lesson was not single vs multiple CPU's it was thread visibility. Single CPU's can have visibility issues e.g. JVM/compiler optimisations.

- the new memory model adds guarantees of visibility as an example volatile and final keywords gain guarantees that you can use to solve the double checked idiom problem you couldn't have used previously.

- The second thread is blocked so no.

- the problem is you effectively have at least two writes this pointer and object contents (obviously usually a lot more), even though in java the object values were written by one thread first and the this second, this ordering can reverse for another thread unless written and read correctly .. a memory barrier gives you this.


That seems contradictory because once you exit the synchronized block everything should be visible.



- Actually everything is visible only if a volatile read is made e.g. another thread is guaranteed to see the changes if it sync's on the same lock as the writer (other methods exist ;-) see the memory model ), basically its visible if the other thread looks correctly.
 
Stephan van Hulst
Bartender
Posts: 15741
368
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Suma Rangaraj wrote:1) so what is the real issue with double checked locking on single vs multi-processor CPUs? How is the new memory model different?


There is no difference. Double checked locking simply doesn't work. Not in the old memory model, not in the new model. The point is that the variable holding the singleton may be set to non-null before the singleton is properly initialized. The initialization will appear to happen before the assignment of the variable only to the thread performing the initialization. There are no guarantees that another thread also perceives the code to be executed in this order, unless that variable was in a synchronized block as well; which with double checked locking, isn't the case.

2) if a thread 1 is executing a synchronized block and Thread 2 preempts thread 1, does it mean thread 1 will have to forcibly exit the synchronized block in between?


No. Once a thread is inside a synchronized block, it will not release the lock unless it calls the wait() method on the object it is synchronized on.
 
Chris Hurst
Ranch Hand
Posts: 443
3
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The new Java memory model allows double check locking if for instance you use volatile for your singleton declaration post the memory model changes, prior to them this wouldn't work. volatile as an example has stronger visibility guarantees in the new memory model.

Use of the guarantees that static, volatile and final acquire (as examples) under the new JMM is probably not best recommended , I would stick with basic synchronisation unless you are very confident.



 
Stephan van Hulst
Bartender
Posts: 15741
368
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Using a volatile variable would defeat the point of using double checked locking in the first place, wouldn't it? You're trading improved performance by avoiding a synchronization for decreased performance by using a volatile variable. So you end up with roughly the same performance, but less readability.
 
Suma Rangaraj
Ranch Hand
Posts: 50
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

No. Once a thread is inside a synchronized block, it will not release the lock unless it calls the wait() method on the object it is synchronized on.



So how can this situation mentioned in the following article be possible?


http://www.ibm.com/developerworks/java/library/j-dcl/index.html (this is an old article too but just trying to understand the preemption in this case].

or even here (this is more recent) - http://blog.adaptivesoftware.biz/2010/10/double-checked-locking-and-java.html

In the section Out-of-Order writes, please check the points 4,5.

Unless the thread 1 is kicked out of synchronized block, how can thread 2 preempt it and return a partially constructed object?

 
Stephan van Hulst
Bartender
Posts: 15741
368
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It isn't kicked out of the synchronized block. Thread 1 simply sets the variable to non-null before the instance is fully constructed. Thread 2 sees that the variable is non-null, and doesn't even attempt to go into the synchronized block, but immediately returns from the method returning the incomplete object.
 
Rancher
Posts: 4804
7
Mac OS X VI Editor Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
And of course, all this is really about the Singleton Pattern, which is evil. See many other threads.
 
Suma Rangaraj
Ranch Hand
Posts: 50
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
thanks all for your responses.
 
Master Rancher
Posts: 5177
83
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Pat Farrell wrote:And of course, all this is really about the Singleton Pattern, which is evil. See many other threads.


Well, double-checked locking is best known in the context of the singleton pattern. But it really applies to any lazily-loaded field, static or not, that requires good access performance in a multi-threaded context. These days the static case is handled more easily and effectively by using an enum - and most "singleton-considered-evil" arguments apply here. But for lazy-loaded instance fields, double-checked locking may be the best solution, now that the memory model has been fixed, if you use volatile. Too bad it's still ugly and easy to screw up.
 
Mike Simmons
Master Rancher
Posts: 5177
83
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:Using a volatile variable would defeat the point of using double checked locking in the first place, wouldn't it? You're trading improved performance by avoiding a synchronization for decreased performance by using a volatile variable. So you end up with roughly the same performance, but less readability.


Maybe. Depends how well it's implemented in the JVM. My impression was that when the new memory model came out (1.5), they did slow down the implementation of volatile, in order to satisfy the more stringent memory model guarantees. And its performance became comparable to synchronized. But as volatile still has fewer guarantees than synchronized does, fundamentally it's still possible to implement it to be faster than synchronization. And in later implementations they've managed to speed volatile up again, so it can be noticeably faster than synchronized. At least, in certain situations.

An important caveat: the above is basically hearsay; I remember reading it somewhere, but can't really vouch for it myself. In any given situation, if the performance really matters, we need to measure it in order to find out whether we're really improving it or not. And it's also extremely common that for a given piece of code, the performance doesn't really matter. As such, double-checked locking isn't worth the trouble, most of the time. But occasionally it may be worth considering.
 
Chris Hurst
Ranch Hand
Posts: 443
3
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I believe volatile is supposed to be quite efficient now and its cost is related to the context of it use (I'm not in anyway recommending its use here).

I think although this is all fun as an exercise, the obvious answer to all this was just use simple synchronization unless your profiler tells you otherwise i.e.
premature optimisation is evil .... again. So although we might go on about options like using volatile I'm hoping this is a learning exercise rather than something we would seriously use.

As regards patterns seems like everyone's pattern is some one else anti pattern so I personally try not to get too religious about the whole thing .. lol

Something I'd find really interesting is how you would unit test something like this , I've seen lots of code that looked to have this type of issue yet be praised for 90% unit test coverage i.e. can you unit test something like this (I have some ideas ;-) ) given that reproducing failure is a problem and if you can't what's that 90% figure really mean particularly as all the unit test over head seemed to impact greatly code reviews , comments, documentation and the like.
 
reply
    Bookmark Topic Watch Topic
  • New Topic