Exforsys

Online Training

Solving Lazy Initialization and double checked locking problem

This is a discussion on Solving Lazy Initialization and double checked locking problem within the Software Patterns forums, part of the Testing category; I have been thinking about the lazy initialization and double checked locking problem. This problem is explain in detail here ...


Go Back   Exforsys > Testing > Software Patterns

Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

Reply

 

LinkBack Thread Tools
  #1 (permalink)  
Old 11-28-2003, 02:32 PM
Vinay Aggarwal
Guest
 
Posts: n/a
Solving Lazy Initialization and double checked locking problem


I have been thinking about the lazy initialization and double checked
locking problem. This problem is explain in detail here
http://www.cs.umd.edu/~pugh/java/mem...edLocking.html
I am not fully convinced that this problem cannot be
solved. I am going to propose a solution here. For the sake of
discussion I will post my solution here. It is possible that the
proposed solution does not work, feedback and comments are welcome.

Here is the original problem. We need to lazy initialize a non static
variable to an instance of a heavy object in a thread safe way. (It is
very easy to safely initialize a static variable). The most commonly
used code is as follows:
---------------------------------------------------------------------------
public class LazyInit
{
private HeavyObject heavyObject =
null;

public HeavyObject
getHeavyObject()
{
if (heavyObject ==
null)
{
synchronized(this)
{
if (heavyObject == null)
{
heavyObject = new HeavyObject();
}
}
}
return
heavyObject;
}
}

---------------------------------------------------------------------------

Unfortunately, this code is broken as described at
http://www.cs.umd.edu/~pugh/java/mem...edLocking.html.
The problem arises from the fact that the optimising compilers can
reorder the constructor call and the assignment to the heavyObject
variable.

In my proposed solution, I am going to use polymorphism to appropriately
syncronize the initialization and after its safe initialization, replace
the implementation itself to be unsynchronized. Here is the code,
detailed description follows.

---------------------------------------------------------------------------
import java.util.*;

public class
LazyInit
// line 3
{
private static HeavyObjectInit heavyObjectInitStatic = new
HeavyObjectInit(); // line 5
private HeavyObjectInit heavyObjectInit = new
HeavyObjectInitSync(); // line 6
private volatile HeavyObject heavyObject =
null; // line 7

static class HeavyObjectInitSync extends
HeavyObjectInit // line 9
{
public HeavyObject getHeavyObject(LazyInit
lazyInit) // line 11
{
HeavyObject heavyObject =
getHeavyObjectInternal(lazyInit); // line 13
lazyInit.heavyObjectInit =
heavyObjectInitStatic; // line 14
return
heavyObject;
// line 15
}

private synchronized HeavyObject getHeavyObjectInternal(LazyInit
lazyInit) // line 18
{
if(lazyInit.heavyObject ==
null) // line 20
{
lazyInit.heavyObject = new
HeavyObject(); // line 22
}
return
lazyInit.heavyObject;
// line 24
}

}

static class
HeavyObjectInit
// line 29
{
public HeavyObject getHeavyObject(LazyInit
lazyInit) // line 31
{
return
lazyInit.heavyObject;
// line 33
}
}

public HeavyObject
getHeavyObject()
// line 37
{
return
heavyObjectInit.getHeavyObject(this);
// line 39
}
}

---------------------------------------------------------------------------

Explanation:
Lets assume this code is executing in a multi threading environment. Now
lets say a few threads enter LazyInit.getHeavyObject() at line 37
simultaneously. These threads will reach
heavyObjectInit.getHeavyObject() at line 39. Since heavyObjectInit is
initialized to HeavyObjectInitSync (at line 6), these threads will enter
getheavyObject() at line 11. At line 13, only one thread (lucky thread)
will be able to enter the syncronized method getHeavyObjectInternal
while rest of threads will be blocked at line 18. The lucky thread will
initialize the heavy object and return it. Since the thread is exiting a
syncronized method and the variable is volatile, the HeavyObject will be
fully initialized before the thread releases the lock. Now the lucky
thread will switch the implementation of heavyObjectInit to a non
syncronized initializer (line 14). Any threads reaching line 39 after
this will call the non syncronized version of getHeavyObject() at line
31. At the same time, all the threads blocked at line 18 will enter the
getHeavyObjectInternal() method one by one and return with the singleton
heavy object instance.

Thus initially a few threads will be synchronized till the lucky thread
switches the initializer. At this time the system will switch to non
syncronized implementation. Note that non syncronized implementation
(line 33) does not even incur the cost of null check as compared to the
original algorithm.

There are some intricacies that I have tried to explain in Q&A form.


Why is the instance of HeavyObjectInitSync nonstatic while instance of
HeavyObjectInit static?
If the HeavyObjectInitSync instance is made static, the syncronized
method will syncronize on the single instance of the class. Since all
instances of LazyInit will refer to single instance of
HeavyObjectInitSync, the call will be mutually exclusive across ALL
instances of LazyInit. Essentially if there are 1000 LazyInit objects
each one wanting to initialize HeavyObjects, these objects will get
initialized sequentially, thus slowing down the process. By making the
instance non static, different instances of LazyInit can initialize the
HeavyObject in parallel.
The HeavyObjectInit instance is static because we dont need one instance
of the HeavyObjectInit class with every instance of LazyInit. This
eliminates unnecessary object creation.

Why is HeavyObjectInitSync class static?
This class can be static or non-static. It is a matter of personal
choice. It should work both ways. I wanted to be consistent with
HeavyObjectInit class.

I have a code sample that shows how different threads will execute.
Download it here http://24.167.121.42/LazyInit.java

The output of this program demonstrates
1. Different threads entering one instance of LazyInit get blocked till
the HeavyObject is initialized.
2. Different threads entering different instances of LazyInit can
initialize the heavy object simultaneously.
3. The HeaveyObject is initialized only once per instance of LazyInit.
4. After the initialization is complete, any other threads entering that
instance of LazyInit do not syncronize anymore.


Vinay Aggarwal
CTO Techlobby
vinay at t e c h l o b b y dot com
h t t p : / / w w w. t e c h l o b b y . c o m /
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #2 (permalink)  
Old 11-28-2003, 07:21 PM
=?iso885915?q?Roger_Lindsj=F6?=
Guest
 
Posts: n/a
Re: Solving Lazy Initialization and double checked locking problem

On Fri, 28 Nov 2003 19:32:23 +0100, Vinay Aggarwal wrote:


> I have been thinking about the lazy initialization and double checked
> locking problem. This problem is explain in detail here
> http://www.cs.umd.edu/~pugh/java/mem...edLocking.html I
> am not fully convinced that this problem cannot be solved. I am going to
> propose a solution here. For the sake of discussion I will post my
> solution here. It is possible that the proposed solution does not work,
> feedback and comments are welcome.


Sorry, but I don't think it works.

> Since the thread is exiting a
> syncronized method and the variable is volatile, the HeavyObject will be
> fully initialized before the thread releases the lock. Now the lucky
> thread will switch the implementation of heavyObjectInit to a non
> syncronized initializer (line 14). Any threads reaching line 39 after
> this will call the non syncronized version of getHeavyObject() at line
> 31. At the same time, all the threads blocked at line 18 will enter the
> getHeavyObjectInternal() method one by one and return with the singleton
> heavy object instance.


Here I think it goes wrong. The JIT should be free to reassign the
instructions as long as it does not change the execution of the current
thread according to the specs. This would allow it to:

lazyInit.heavyObjectInit = heavyObjectInitStatic; // line 14

before line 13 since this does not change anything for the executing
thread. However, now another thread can enter LazyInit.getHeavyObject()
and get the non synchronized implementation with an uninitialized object
before the first thread has had a chance to fully create the heavy
object.

So the second thread could return a null object or a not fully
initialized object.

BTW, comp.lang.java does not exist.

//Roger Lindsjö
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #3 (permalink)  
Old 11-28-2003, 07:33 PM
Vinay Aggarwal
Guest
 
Posts: n/a
Re: Solving Lazy Initialization and double checked locking problem


Hey Roger,

That was a nice catch. I missed that one.

Now lets follow this logic. The compiler can only reorder the statements
if it does not change anything for the currently executing thread.
So can we create a side effect?

What if I change the inner class to something as follows.


static class HeavyObjectInitSync extends
HeavyObjectInit // line 9
{
public volatile int i=0;
public HeavyObject getHeavyObject(LazyInit
lazyInit) // line 11
{
HeavyObject heavyObject =
getHeavyObjectInternal(lazyInit); // line 13
if(i>0)
lazyInit.heavyObjectInit =
heavyObjectInitStatic; // line 14
return
heavyObject;
// line 15
}

private synchronized HeavyObject getHeavyObjectInternal(LazyInit
lazyInit) // line 18
{
if(lazyInit.heavyObject ==
null) // line 20
{
lazyInit.heavyObject = new
HeavyObject(); // line 22
}
i++;
return
lazyInit.heavyObject;
// line 24
}
}

Now the compiler is bound to keep them in straight order. What do you
think?

Vinay Aggarwal
CTO Techlobby
vinay at t e c h l o b b y dot com
h t t p : / / w w w. t e c h l o b b y . c o m /


Roger Lindsjö wrote:
>
> On Fri, 28 Nov 2003 19:32:23 +0100, Vinay Aggarwal wrote:
>
> > I have been thinking about the lazy initialization and double checked
> > locking problem. This problem is explain in detail here
> > http://www.cs.umd.edu/~pugh/java/mem...edLocking.html I
> > am not fully convinced that this problem cannot be solved. I am going to
> > propose a solution here. For the sake of discussion I will post my
> > solution here. It is possible that the proposed solution does not work,
> > feedback and comments are welcome.

>
> Sorry, but I don't think it works.
>
> > Since the thread is exiting a
> > syncronized method and the variable is volatile, the HeavyObject will be
> > fully initialized before the thread releases the lock. Now the lucky
> > thread will switch the implementation of heavyObjectInit to a non
> > syncronized initializer (line 14). Any threads reaching line 39 after
> > this will call the non syncronized version of getHeavyObject() at line
> > 31. At the same time, all the threads blocked at line 18 will enter the
> > getHeavyObjectInternal() method one by one and return with the singleton
> > heavy object instance.

>
> Here I think it goes wrong. The JIT should be free to reassign the
> instructions as long as it does not change the execution of the current
> thread according to the specs. This would allow it to:
>
> lazyInit.heavyObjectInit = heavyObjectInitStatic; // line 14
>
> before line 13 since this does not change anything for the executing
> thread. However, now another thread can enter LazyInit.getHeavyObject()
> and get the non synchronized implementation with an uninitialized object
> before the first thread has had a chance to fully create the heavy
> object.
>
> So the second thread could return a null object or a not fully
> initialized object.
>
> BTW, comp.lang.java does not exist.
>
> //Roger Lindsjö

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #4 (permalink)  
Old 11-29-2003, 12:53 PM
pete kirkham
Guest
 
Posts: n/a
Re: Solving Lazy Initialization and double checked locking problem

DCL is not much of a problem in the real world. AFAIK no-one has ever
given an example of a profiled application on a modern JVM where the
additional overhead of a synchronized call makes enough of a difference
to use complex DCL alternatives. Show me some code that
does something useful and has at least a 10% improvement in speed in its
critical path by making a faster synchronization mechanism for singletons.

The common solutions to lazy creation are to use class/instance
synchronization (singletons and per-instance resources):

[static] HeavyObject heavyObject;
public [static] synchronized getHeavyObject () {
if (heavyObject==null) {
heavyObject = new HeavyObject();
}
return heavyObject;
}

or the first-call synchronization implicit in class loading (singletons
only):

class HeavyObjectGuardian {
static HeavyObject heavyObject = new HeavyObject();
}

public static getHeavyObject () {
return HeavyObjectGuardian.heavyObject;
}

Edge cases exist where the singleton needs to be released, but your
example doesn't help that in its current form - that would require safe
setting of the heavyObjectInit field, and so you're back to square one
synchronizing that.

On a single or dual processor machine with a recent JVM, a synchronized
method call is only very slightly slower than an non-synchronized call -
DCL was an artifact to get round the slow synchronization in early JVMs.

Speed was the only reason to use DCL in the first place. DCL compromised
deterministic thread safety with probabalistic thread safety (there are
no recorded examples of it failing, but it is theoretically possible) in
order to gain a speed advantage by not using synchronization, as
synchronization was costly at the time.

Therefore alternatives to DCL must be deterministically thread safe (you
can still use DCL if you only need probable safety - if a plane journey
were as safe as a DCL access, then you could travel every day for a
million years and never crash), and either faster or simpler than the
two patterns above to be worthwhile. Those two examples are thread safe,
so execution speed is the *only* criteria to judge a different thread
safe pattern against them.

Plot a graph showing how much faster your method is on single, dual and
multiple processors architectures when compared to the two normal
solutions above, and explain why the additional complexity is worth the
effort in a typical application, where method invocation overhead is a
very minor cost. Without profiling your pattern in a realistic
sscenario, there is nothing to judge its merit, and the simplist
solution wins.


Pete

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #5 (permalink)  
Old 11-30-2003, 01:02 AM
Vinay Aggarwal
Guest
 
Posts: n/a
Re: Solving Lazy Initialization and double checked locking problem


Hey Pete,

I do agree with you on some points and disagree on others. You are
correct that mostly this problem doesn't bother us in real world.
Syncronizing the whole method usually is good enough. However I cannot
say that every application in the world will be better off with
syncronizing the get method. It may be true, it may not. I will
let individual application authors decide what they want to use.
I believe there are applications where reliability and responsiveness
is much more important than solution complexity. For example
stock trading applications or infrastructure pieces like EJB
containers.

My solution does seems complicated than DCL but well its the only
deterministic alternative to method syncronization for instance based
singletons. Individual application authors have to decide for
themselves about how much do they stand to gain with different
implementations. The performance can have huge variation depending on
the application architecture. Hence any numbers I provide are
probably not useful in real world.

One of my motives of solving the problem was just to take a shot at
a problem that experts say cannot be solved. Not only that, I also
believe that this pattern can be used to solve other problems as
well. For example, you mentioned that releasing the singletons is
an issue for some cases. My solution can possibly be extended to
solve such problems.

This whole exercise could be just theoretical. Its out there
in case somebody wants to use it. If there are efforts to change
memory models and threading specifications to solve this problem,
my solution probably interests somebody.

Vinay Aggarwal
CTO Techlobby
vinay at t e c h l o b b y dot com
h t t p : / / w w w. t e c h l o b b y . c o m /



pete kirkham wrote:
>
> DCL is not much of a problem in the real world. AFAIK no-one has ever
> given an example of a profiled application on a modern JVM where the
> additional overhead of a synchronized call makes enough of a difference
> to use complex DCL alternatives. Show me some code that
> does something useful and has at least a 10% improvement in speed in its
> critical path by making a faster synchronization mechanism for singletons.
>
> The common solutions to lazy creation are to use class/instance
> synchronization (singletons and per-instance resources):
>
> [static] HeavyObject heavyObject;
> public [static] synchronized getHeavyObject () {
> if (heavyObject==null) {
> heavyObject = new HeavyObject();
> }
> return heavyObject;
> }
>
> or the first-call synchronization implicit in class loading (singletons
> only):
>
> class HeavyObjectGuardian {
> static HeavyObject heavyObject = new HeavyObject();
> }
>
> public static getHeavyObject () {
> return HeavyObjectGuardian.heavyObject;
> }
>
> Edge cases exist where the singleton needs to be released, but your
> example doesn't help that in its current form - that would require safe
> setting of the heavyObjectInit field, and so you're back to square one
> synchronizing that.
>
> On a single or dual processor machine with a recent JVM, a synchronized
> method call is only very slightly slower than an non-synchronized call -
> DCL was an artifact to get round the slow synchronization in early JVMs.
>
> Speed was the only reason to use DCL in the first place. DCL compromised
> deterministic thread safety with probabalistic thread safety (there are
> no recorded examples of it failing, but it is theoretically possible) in
> order to gain a speed advantage by not using synchronization, as
> synchronization was costly at the time.
>
> Therefore alternatives to DCL must be deterministically thread safe (you
> can still use DCL if you only need probable safety - if a plane journey
> were as safe as a DCL access, then you could travel every day for a
> million years and never crash), and either faster or simpler than the
> two patterns above to be worthwhile. Those two examples are thread safe,
> so execution speed is the *only* criteria to judge a different thread
> safe pattern against them.
>
> Plot a graph showing how much faster your method is on single, dual and
> multiple processors architectures when compared to the two normal
> solutions above, and explain why the additional complexity is worth the
> effort in a typical application, where method invocation overhead is a
> very minor cost. Without profiling your pattern in a realistic
> sscenario, there is nothing to judge its merit, and the simplist
> solution wins.
>
> Pete

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #6 (permalink)  
Old 11-30-2003, 01:02 AM
Vinay Aggarwal
Guest
 
Posts: n/a
Re: Solving Lazy Initialization and double checked locking problem


Hey Pete,

I do agree with you on some points and disagree on others. You are
correct that mostly this problem doesn't bother us in real world.
Syncronizing the whole method usually is good enough. However I cannot
say that every application in the world will be better off with
syncronizing the get method. It may be true, it may not. I will
let individual application authors decide what they want to use.
I believe there are applications where reliability and responsiveness
is much more important than solution complexity. For example
stock trading applications or infrastructure pieces like EJB
containers.

My solution does seems complicated than DCL but well its the only
deterministic alternative to method syncronization for instance based
singletons. Individual application authors have to decide for
themselves about how much do they stand to gain with different
implementations. The performance can have huge variation depending on
the application architecture. Hence any numbers I provide are
probably not useful in real world.

One of my motives of solving the problem was just to take a shot at
a problem that experts say cannot be solved. Not only that, I also
believe that this pattern can be used to solve other problems as
well. For example, you mentioned that releasing the singletons is
an issue for some cases. My solution can possibly be extended to
solve such problems.

This whole exercise could be just theoretical. Its out there
in case somebody wants to use it. If there are efforts to change
memory models and threading specifications to solve this problem,
my solution probably interests somebody.

Vinay Aggarwal
CTO Techlobby
vinay at t e c h l o b b y dot com
h t t p : / / w w w. t e c h l o b b y . c o m /



pete kirkham wrote:
>
> DCL is not much of a problem in the real world. AFAIK no-one has ever
> given an example of a profiled application on a modern JVM where the
> additional overhead of a synchronized call makes enough of a difference
> to use complex DCL alternatives. Show me some code that
> does something useful and has at least a 10% improvement in speed in its
> critical path by making a faster synchronization mechanism for singletons.
>
> The common solutions to lazy creation are to use class/instance
> synchronization (singletons and per-instance resources):
>
> [static] HeavyObject heavyObject;
> public [static] synchronized getHeavyObject () {
> if (heavyObject==null) {
> heavyObject = new HeavyObject();
> }
> return heavyObject;
> }
>
> or the first-call synchronization implicit in class loading (singletons
> only):
>
> class HeavyObjectGuardian {
> static HeavyObject heavyObject = new HeavyObject();
> }
>
> public static getHeavyObject () {
> return HeavyObjectGuardian.heavyObject;
> }
>
> Edge cases exist where the singleton needs to be released, but your
> example doesn't help that in its current form - that would require safe
> setting of the heavyObjectInit field, and so you're back to square one
> synchronizing that.
>
> On a single or dual processor machine with a recent JVM, a synchronized
> method call is only very slightly slower than an non-synchronized call -
> DCL was an artifact to get round the slow synchronization in early JVMs.
>
> Speed was the only reason to use DCL in the first place. DCL compromised
> deterministic thread safety with probabalistic thread safety (there are
> no recorded examples of it failing, but it is theoretically possible) in
> order to gain a speed advantage by not using synchronization, as
> synchronization was costly at the time.
>
> Therefore alternatives to DCL must be deterministically thread safe (you
> can still use DCL if you only need probable safety - if a plane journey
> were as safe as a DCL access, then you could travel every day for a
> million years and never crash), and either faster or simpler than the
> two patterns above to be worthwhile. Those two examples are thread safe,
> so execution speed is the *only* criteria to judge a different thread
> safe pattern against them.
>
> Plot a graph showing how much faster your method is on single, dual and
> multiple processors architectures when compared to the two normal
> solutions above, and explain why the additional complexity is worth the
> effort in a typical application, where method invocation overhead is a
> very minor cost. Without profiling your pattern in a realistic
> sscenario, there is nothing to judge its merit, and the simplist
> solution wins.
>
> Pete

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #7 (permalink)  
Old 11-30-2003, 01:02 AM
Vinay Aggarwal
Guest
 
Posts: n/a
Re: Solving Lazy Initialization and double checked locking problem


Hey Pete,

I do agree with you on some points and disagree on others. You are
correct that mostly this problem doesn't bother us in real world.
Syncronizing the whole method usually is good enough. However I cannot
say that every application in the world will be better off with
syncronizing the get method. It may be true, it may not. I will
let individual application authors decide what they want to use.
I believe there are applications where reliability and responsiveness
is much more important than solution complexity. For example
stock trading applications or infrastructure pieces like EJB
containers.

My solution does seems complicated than DCL but well its the only
deterministic alternative to method syncronization for instance based
singletons. Individual application authors have to decide for
themselves about how much do they stand to gain with different
implementations. The performance can have huge variation depending on
the application architecture. Hence any numbers I provide are
probably not useful in real world.

One of my motives of solving the problem was just to take a shot at
a problem that experts say cannot be solved. Not only that, I also
believe that this pattern can be used to solve other problems as
well. For example, you mentioned that releasing the singletons is
an issue for some cases. My solution can possibly be extended to
solve such problems.

This whole exercise could be just theoretical. Its out there
in case somebody wants to use it. If there are efforts to change
memory models and threading specifications to solve this problem,
my solution probably interests somebody.

Vinay Aggarwal
CTO Techlobby
vinay at t e c h l o b b y dot com
h t t p : / / w w w. t e c h l o b b y . c o m /



pete kirkham wrote:
>
> DCL is not much of a problem in the real world. AFAIK no-one has ever
> given an example of a profiled application on a modern JVM where the
> additional overhead of a synchronized call makes enough of a difference
> to use complex DCL alternatives. Show me some code that
> does something useful and has at least a 10% improvement in speed in its
> critical path by making a faster synchronization mechanism for singletons.
>
> The common solutions to lazy creation are to use class/instance
> synchronization (singletons and per-instance resources):
>
> [static] HeavyObject heavyObject;
> public [static] synchronized getHeavyObject () {
> if (heavyObject==null) {
> heavyObject = new HeavyObject();
> }
> return heavyObject;
> }
>
> or the first-call synchronization implicit in class loading (singletons
> only):
>
> class HeavyObjectGuardian {
> static HeavyObject heavyObject = new HeavyObject();
> }
>
> public static getHeavyObject () {
> return HeavyObjectGuardian.heavyObject;
> }
>
> Edge cases exist where the singleton needs to be released, but your
> example doesn't help that in its current form - that would require safe
> setting of the heavyObjectInit field, and so you're back to square one
> synchronizing that.
>
> On a single or dual processor machine with a recent JVM, a synchronized
> method call is only very slightly slower than an non-synchronized call -
> DCL was an artifact to get round the slow synchronization in early JVMs.
>
> Speed was the only reason to use DCL in the first place. DCL compromised
> deterministic thread safety with probabalistic thread safety (there are
> no recorded examples of it failing, but it is theoretically possible) in
> order to gain a speed advantage by not using synchronization, as
> synchronization was costly at the time.
>
> Therefore alternatives to DCL must be deterministically thread safe (you
> can still use DCL if you only need probable safety - if a plane journey
> were as safe as a DCL access, then you could travel every day for a
> million years and never crash), and either faster or simpler than the
> two patterns above to be worthwhile. Those two examples are thread safe,
> so execution speed is the *only* criteria to judge a different thread
> safe pattern against them.
>
> Plot a graph showing how much faster your method is on single, dual and
> multiple processors architectures when compared to the two normal
> solutions above, and explain why the additional complexity is worth the
> effort in a typical application, where method invocation overhead is a
> very minor cost. Without profiling your pattern in a realistic
> sscenario, there is nothing to judge its merit, and the simplist
> solution wins.
>
> Pete

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #8 (permalink)  
Old 11-30-2003, 01:02 AM
Vinay Aggarwal
Guest
 
Posts: n/a
Re: Solving Lazy Initialization and double checked locking problem


Hey Pete,

I do agree with you on some points and disagree on others. You are
correct that mostly this problem doesn't bother us in real world.
Syncronizing the whole method usually is good enough. However I cannot
say that every application in the world will be better off with
syncronizing the get method. It may be true, it may not. I will
let individual application authors decide what they want to use.
I believe there are applications where reliability and responsiveness
is much more important than solution complexity. For example
stock trading applications or infrastructure pieces like EJB
containers.

My solution does seems complicated than DCL but well its the only
deterministic alternative to method syncronization for instance based
singletons. Individual application authors have to decide for
themselves about how much do they stand to gain with different
implementations. The performance can have huge variation depending on
the application architecture. Hence any numbers I provide are
probably not useful in real world.

One of my motives of solving the problem was just to take a shot at
a problem that experts say cannot be solved. Not only that, I also
believe that this pattern can be used to solve other problems as
well. For example, you mentioned that releasing the singletons is
an issue for some cases. My solution can possibly be extended to
solve such problems.

This whole exercise could be just theoretical. Its out there
in case somebody wants to use it. If there are efforts to change
memory models and threading specifications to solve this problem,
my solution probably interests somebody.

Vinay Aggarwal
CTO Techlobby
vinay at t e c h l o b b y dot com
h t t p : / / w w w. t e c h l o b b y . c o m /



pete kirkham wrote:
>
> DCL is not much of a problem in the real world. AFAIK no-one has ever
> given an example of a profiled application on a modern JVM where the
> additional overhead of a synchronized call makes enough of a difference
> to use complex DCL alternatives. Show me some code that
> does something useful and has at least a 10% improvement in speed in its
> critical path by making a faster synchronization mechanism for singletons.
>
> The common solutions to lazy creation are to use class/instance
> synchronization (singletons and per-instance resources):
>
> [static] HeavyObject heavyObject;
> public [static] synchronized getHeavyObject () {
> if (heavyObject==null) {
> heavyObject = new HeavyObject();
> }
> return heavyObject;
> }
>
> or the first-call synchronization implicit in class loading (singletons
> only):
>
> class HeavyObjectGuardian {
> static HeavyObject heavyObject = new HeavyObject();
> }
>
> public static getHeavyObject () {
> return HeavyObjectGuardian.heavyObject;
> }
>
> Edge cases exist where the singleton needs to be released, but your
> example doesn't help that in its current form - that would require safe
> setting of the heavyObjectInit field, and so you're back to square one
> synchronizing that.
>
> On a single or dual processor machine with a recent JVM, a synchronized
> method call is only very slightly slower than an non-synchronized call -
> DCL was an artifact to get round the slow synchronization in early JVMs.
>
> Speed was the only reason to use DCL in the first place. DCL compromised
> deterministic thread safety with probabalistic thread safety (there are
> no recorded examples of it failing, but it is theoretically possible) in
> order to gain a speed advantage by not using synchronization, as
> synchronization was costly at the time.
>
> Therefore alternatives to DCL must be deterministically thread safe (you
> can still use DCL if you only need probable safety - if a plane journey
> were as safe as a DCL access, then you could travel every day for a
> million years and never crash), and either faster or simpler than the
> two patterns above to be worthwhile. Those two examples are thread safe,
> so execution speed is the *only* criteria to judge a different thread
> safe pattern against them.
>
> Plot a graph showing how much faster your method is on single, dual and
> multiple processors architectures when compared to the two normal
> solutions above, and explain why the additional complexity is worth the
> effort in a typical application, where method invocation overhead is a
> very minor cost. Without profiling your pattern in a realistic
> sscenario, there is nothing to judge its merit, and the simplist
> solution wins.
>
> Pete

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #9 (permalink)  
Old 11-30-2003, 01:02 AM
Vinay Aggarwal
Guest
 
Posts: n/a
Re: Solving Lazy Initialization and double checked locking problem


Hey Pete,

I do agree with you on some points and disagree on others. You are
correct that mostly this problem doesn't bother us in real world.
Syncronizing the whole method usually is good enough. However I cannot
say that every application in the world will be better off with
syncronizing the get method. It may be true, it may not. I will
let individual application authors decide what they want to use.
I believe there are applications where reliability and responsiveness
is much more important than solution complexity. For example
stock trading applications or infrastructure pieces like EJB
containers.

My solution does seems complicated than DCL but well its the only
deterministic alternative to method syncronization for instance based
singletons. Individual application authors have to decide for
themselves about how much do they stand to gain with different
implementations. The performance can have huge variation depending on
the application architecture. Hence any numbers I provide are
probably not useful in real world.

One of my motives of solving the problem was just to take a shot at
a problem that experts say cannot be solved. Not only that, I also
believe that this pattern can be used to solve other problems as
well. For example, you mentioned that releasing the singletons is
an issue for some cases. My solution can possibly be extended to
solve such problems.

This whole exercise could be just theoretical. Its out there
in case somebody wants to use it. If there are efforts to change
memory models and threading specifications to solve this problem,
my solution probably interests somebody.

Vinay Aggarwal
CTO Techlobby
vinay at t e c h l o b b y dot com
h t t p : / / w w w. t e c h l o b b y . c o m /



pete kirkham wrote:
>
> DCL is not much of a problem in the real world. AFAIK no-one has ever
> given an example of a profiled application on a modern JVM where the
> additional overhead of a synchronized call makes enough of a difference
> to use complex DCL alternatives. Show me some code that
> does something useful and has at least a 10% improvement in speed in its
> critical path by making a faster synchronization mechanism for singletons.
>
> The common solutions to lazy creation are to use class/instance
> synchronization (singletons and per-instance resources):
>
> [static] HeavyObject heavyObject;
> public [static] synchronized getHeavyObject () {
> if (heavyObject==null) {
> heavyObject = new HeavyObject();
> }
> return heavyObject;
> }
>
> or the first-call synchronization implicit in class loading (singletons
> only):
>
> class HeavyObjectGuardian {
> static HeavyObject heavyObject = new HeavyObject();
> }
>
> public static getHeavyObject () {
> return HeavyObjectGuardian.heavyObject;
> }
>
> Edge cases exist where the singleton needs to be released, but your
> example doesn't help that in its current form - that would require safe
> setting of the heavyObjectInit field, and so you're back to square one
> synchronizing that.
>
> On a single or dual processor machine with a recent JVM, a synchronized
> method call is only very slightly slower than an non-synchronized call -
> DCL was an artifact to get round the slow synchronization in early JVMs.
>
> Speed was the only reason to use DCL in the first place. DCL compromised
> deterministic thread safety with probabalistic thread safety (there are
> no recorded examples of it failing, but it is theoretically possible) in
> order to gain a speed advantage by not using synchronization, as
> synchronization was costly at the time.
>
> Therefore alternatives to DCL must be deterministically thread safe (you
> can still use DCL if you only need probable safety - if a plane journey
> were as safe as a DCL access, then you could travel every day for a
> million years and never crash), and either faster or simpler than the
> two patterns above to be worthwhile. Those two examples are thread safe,
> so execution speed is the *only* criteria to judge a different thread
> safe pattern against them.
>
> Plot a graph showing how much faster your method is on single, dual and
> multiple processors architectures when compared to the two normal
> solutions above, and explain why the additional complexity is worth the
> effort in a typical application, where method invocation overhead is a
> very minor cost. Without profiling your pattern in a realistic
> sscenario, there is nothing to judge its merit, and the simplist
> solution wins.
>
> Pete

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #10 (permalink)  
Old 11-30-2003, 01:04 AM
Vinay Aggarwal
Guest
 
Posts: n/a
Re: Solving Lazy Initialization and double checked locking problem


Hey Pete,

I do agree with you on some points and disagree on others. You are
correct that mostly this problem doesn't bother us in real world.
Syncronizing the whole method usually is good enough. However I cannot
say that every application in the world will be better off with
syncronizing the get method. It may be true, it may not. I will
let individual application authors decide what they want to use.
I believe there are applications where reliability and responsiveness
is much more important than solution complexity. For example
stock trading applications or infrastructure pieces like EJB
containers.

My solution does seems complicated than DCL but well its the only
deterministic alternative to method syncronization for instance based
singletons. Individual application authors have to decide for
themselves about how much do they stand to gain with different
implementations. The performance can have huge variation depending on
the application architecture. Hence any numbers I provide are
probably not useful in real world.

One of my motives of solving the problem was just to take a shot at
a problem that experts say cannot be solved. Not only that, I also
believe that this pattern can be used to solve other problems as
well. For example, you mentioned that releasing the singletons is
an issue for some cases. My solution can possibly be extended to
solve such problems.

This whole exercise could be just theoretical. Its out there
in case somebody wants to use it. If there are efforts to change
memory models and threading specifications to solve this problem,
my solution probably interests somebody.

Vinay Aggarwal
CTO Techlobby
vinay at t e c h l o b b y dot com
h t t p : / / w w w. t e c h l o b b y . c o m /



pete kirkham wrote:
>
> DCL is not much of a problem in the real world. AFAIK no-one has ever
> given an example of a profiled application on a modern JVM where the
> additional overhead of a synchronized call makes enough of a difference
> to use complex DCL alternatives. Show me some code that
> does something useful and has at least a 10% improvement in speed in its
> critical path by making a faster synchronization mechanism for singletons.
>
> The common solutions to lazy creation are to use class/instance
> synchronization (singletons and per-instance resources):
>
> [static] HeavyObject heavyObject;
> public [static] synchronized getHeavyObject () {
> if (heavyObject==null) {
> heavyObject = new HeavyObject();
> }
> return heavyObject;
> }
>
> or the first-call synchronization implicit in class loading (singletons
> only):
>
> class HeavyObjectGuardian {
> static HeavyObject heavyObject = new HeavyObject();
> }
>
> public static getHeavyObject () {
> return HeavyObjectGuardian.heavyObject;
> }
>
> Edge cases exist where the singleton needs to be released, but your
> example doesn't help that in its current form - that would require safe
> setting of the heavyObjectInit field, and so you're back to square one
> synchronizing that.
>
> On a single or dual processor machine with a recent JVM, a synchronized
> method call is only very slightly slower than an non-synchronized call -
> DCL was an artifact to get round the slow synchronization in early JVMs.
>
> Speed was the only reason to use DCL in the first place. DCL compromised
> deterministic thread safety with probabalistic thread safety (there are
> no recorded examples of it failing, but it is theoretically possible) in
> order to gain a speed advantage by not using synchronization, as
> synchronization was costly at the time.
>
> Therefore alternatives to DCL must be deterministically thread safe (you
> can still use DCL if you only need probable safety - if a plane journey
> were as safe as a DCL access, then you could travel every day for a
> million years and never crash), and either faster or simpler than the
> two patterns above to be worthwhile. Those two examples are thread safe,
> so execution speed is the *only* criteria to judge a different thread
> safe pattern against them.
>
> Plot a graph showing how much faster your method is on single, dual and
> multiple processors architectures when compared to the two normal
> solutions above, and explain why the additional complexity is worth the
> effort in a typical application, where method invocation overhead is a
> very minor cost. Without profiling your pattern in a realistic
> sscenario, there is nothing to judge its merit, and the simplist
> solution wins.
>
> Pete


Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



All times are GMT -4. The time now is 07:56 AM.


Powered by vBulletin® Version 3.7.3
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.1.0
Copyright 2004 - 2007 Exforsys Inc. All rights reserved.