473,545 Members | 289 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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(th is)
{
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 heavyObjectInit Static = new
HeavyObjectInit (); // line 5
private HeavyObjectInit heavyObjectInit = new
HeavyObjectInit Sync(); // line 6
private volatile HeavyObject heavyObject =
null; // line 7

static class HeavyObjectInit Sync extends
HeavyObjectInit // line 9
{
public HeavyObject getHeavyObject( LazyInit
lazyInit) // line 11
{
HeavyObject heavyObject =
getHeavyObjectI nternal(lazyIni t); // line 13
lazyInit.heavyO bjectInit =
heavyObjectInit Static; // line 14
return
heavyObject;
// line 15
}

private synchronized HeavyObject getHeavyObjectI nternal(LazyIni t
lazyInit) // line 18
{
if(lazyInit.hea vyObject ==
null) // line 20
{
lazyInit.heavyO bject = new
HeavyObject(); // line 22
}
return
lazyInit.heavyO bject;
// line 24
}

}

static class
HeavyObjectInit
// line 29
{
public HeavyObject getHeavyObject( LazyInit
lazyInit) // line 31
{
return
lazyInit.heavyO bject;
// 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.getHea vyObject() at line 37
simultaneously. These threads will reach
heavyObjectInit .getHeavyObject () at line 39. Since heavyObjectInit is
initialized to HeavyObjectInit Sync (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 getHeavyObjectI nternal
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
getHeavyObjectI nternal() 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 HeavyObjectInit Sync nonstatic while instance of
HeavyObjectInit static?
If the HeavyObjectInit Sync 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
HeavyObjectInit Sync, 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 HeavyObjectInit Sync 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 /
Jul 17 '05 #1
2 4021
Hi Vinay,

Unless 'synchronized' blocks cause unacceptable performance issues, just use
them.
Otherwise, take a look at this:
http://gee.cs.oswego.edu/dl/classes/...urrent/intro.h
tml

We use it in our software, for lazy caching of certain objects (using
ConcurrentReade rHashMap).
It works great! And the use of this package is free. No license needed.

-- Anton.

"Vinay Aggarwal" <vi******@h-o-t-m-a-i-l.com> wrote in message
news:Xw******** *********@twist er.austin.rr.co m...

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(th is)
{
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 heavyObjectInit Static = new
HeavyObjectInit (); // line 5
private HeavyObjectInit heavyObjectInit = new
HeavyObjectInit Sync(); // line 6
private volatile HeavyObject heavyObject =
null; // line 7

static class HeavyObjectInit Sync extends
HeavyObjectInit // line 9
{
public HeavyObject getHeavyObject( LazyInit
lazyInit) // line 11
{
HeavyObject heavyObject =
getHeavyObjectI nternal(lazyIni t); // line 13
lazyInit.heavyO bjectInit =
heavyObjectInit Static; // line 14
return
heavyObject;
// line 15
}

private synchronized HeavyObject getHeavyObjectI nternal(LazyIni t
lazyInit) // line 18
{
if(lazyInit.hea vyObject ==
null) // line 20
{
lazyInit.heavyO bject = new
HeavyObject(); // line 22
}
return
lazyInit.heavyO bject;
// line 24
}

}

static class
HeavyObjectInit
// line 29
{
public HeavyObject getHeavyObject( LazyInit
lazyInit) // line 31
{
return
lazyInit.heavyO bject;
// 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.getHea vyObject() at line 37
simultaneously. These threads will reach
heavyObjectInit .getHeavyObject () at line 39. Since heavyObjectInit is
initialized to HeavyObjectInit Sync (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 getHeavyObjectI nternal
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
getHeavyObjectI nternal() 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 HeavyObjectInit Sync nonstatic while instance of
HeavyObjectInit static?
If the HeavyObjectInit Sync 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
HeavyObjectInit Sync, 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 HeavyObjectInit Sync 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 /

Jul 17 '05 #2
On Fri, 28 Nov 2003 18:32:23 +0000, 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.

I know this thread is getting old but I had an interview with someone who
claims to have solved the DCL paradox. When I look at this I cannot help
but think that if it were that simple many people would have solved it by
now.> 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(th is)
{
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 heavyObjectInit Static = new
HeavyObjectInit (); // line 5
private HeavyObjectInit heavyObjectInit = new
HeavyObjectInit Sync(); // line 6
private volatile HeavyObject heavyObject =
null; // line 7

static class HeavyObjectInit Sync extends
HeavyObjectInit // line 9
{
public HeavyObject getHeavyObject( LazyInit
lazyInit) // line 11
{
HeavyObject heavyObject =
getHeavyObjectI nternal(lazyIni t); // line 13
lazyInit.heavyO bjectInit =
heavyObjectInit Static; // line 14
return
heavyObject;
// line 15
}

private synchronized HeavyObject getHeavyObjectI nternal(LazyIni t
lazyInit) // line 18
{
if(lazyInit.hea vyObject ==
null) // line 20
{
lazyInit.heavyO bject = new
HeavyObject(); // line 22
}
return
lazyInit.heavyO bject;
// line 24
}

}

static class
HeavyObjectInit
// line 29
{
public HeavyObject getHeavyObject( LazyInit
lazyInit) // line 31
{
return
lazyInit.heavyO bject;
// 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.getHea vyObject() at line 37
simultaneously. These threads will reach
heavyObjectInit .getHeavyObject () at line 39. Since heavyObjectInit is
initialized to HeavyObjectInit Sync (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 getHeavyObjectI nternal
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
getHeavyObjectI nternal() 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 HeavyObjectInit Sync nonstatic while instance of
HeavyObjectInit static?
If the HeavyObjectInit Sync 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
HeavyObjectInit Sync, 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 HeavyObjectInit Sync 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 /

public class Singleton {
private static Singleton _instance;

public Singleton getInstance() {
if(_instance == null ) {
_instance = createInstance( );
}

return _instance;
}

private synchronized Singleton createInstance( ) {
if(_instance == null) {
return new Singleton;
}
}
}
Jul 17 '05 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

12
2789
by: Siemel Naran | last post by:
What is a good idiom for handling a lazy object? I see 2 good possibilities. Any more, any comments? Which way do people here use? (1) class Thing { public: Thing(double x, double y) : x(x), y(y), calculated(false) { } double operator()() const {
7
2466
by: Drew McCormack | last post by:
I have a C++ template class which contains a static variable whose construction registers the class with a map. Something like this: template <typename T> class M { static Registrar<M> registrar; }; The constructor of Registrar does the registering when it is initialized.
4
2181
by: Bret Pehrson | last post by:
I just stumbled across the following problem: //.h class Masses { static double mass1; static double mass2; static double mass3; };
16
3235
by: Martin Jørgensen | last post by:
Hi, I've made a program from numerical recipes. Looks like I'm not allowed to distribute the source code from numerical recipes but it shouldn't even be necessary to do that. My problem is that I'm not very experienced with pointers, pointers to pointers and the like and I got 4 compiler warnings + I don't completely understand how to...
3
1879
by: JohnQ | last post by:
SomeObject* instance() // flawed way { static SomeObject* instance = NULL; LockThing(); // locking even when not required if(instance == NULL) // instance may still be NULL when another thread checks instance = new SomeObject(); UnlockThing(); // oh dang, more unnecessary function calls after first pass return instance;
3
5833
by: Steve Folly | last post by:
Hi, I had a problem in my code recently which turned out to be the 'the "static initialization order fiasco"' problem (<http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12>) The FAQ section describes a solution using methods returning references to static objects. But consider:
8
2437
by: claudiu | last post by:
Hi, I have a question on the double checked locking. The classic implementation (shamelessly copied from Scott Meyers' and Andrei Alexandrescu's article) class Singleton { public: static Singleton* instance(); ....
0
1185
by: George2 | last post by:
Hello gurus, For the wellknown Double-Checked Locking pattern, http://www.ddj.com/184405726?pgno=1 Step 1: Allocate memory to hold a Singleton object. Step 2: Construct a Singleton object in the allocated memory. Step 3: Make pInstance point to the allocated memory.
9
11163
by: Rohit | last post by:
I am trying to initialize an array whose initializers depend on value of Enums. I take enum and then decide the initializer value, so that even if enum value changes because of addition to list even then I should be able to get correct value for the array element. I need value and state to be present in a single byte thats why I use macros. ...
0
7465
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7398
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
7656
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
1
7416
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
5969
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5325
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
3449
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
1
1878
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
1
1013
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.