|
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
|