Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Thread-safe Singleton Design Implementation

5 views
Skip to first unread message

yaru22

unread,
Jul 30, 2007, 1:31:15 PM7/30/07
to
I was reading Wikipedia about Singleton Design pattern and it had some
sample codes for the implementation.

Under Java example implementation, there was "A thread-safe Java
programming language lazy-loaded solution." But I don't understand why
it is thread-safe & lazy-loaded solution. Could anyone explain it?

This is the source code from the Wikipedia (http://en.wikipedia.org/
wiki/Singleton_pattern) :
public class Singleton
{
// Private constructor suppresses generation of a (public) default
constructor
private Singleton() {}

private static class SingletonHolder
{
private final static Singleton INSTANCE = new Singleton();
}

public static Singleton getInstance()
{
return SingletonHolder.INSTANCE;
}
}

Thank you.

Eric Sosman

unread,
Jul 30, 2007, 3:00:41 PM7/30/07
to
yaru22 wrote On 07/30/07 13:31,:

Bloch explains this technique in "Effective Java."

It is lazy-loaded because the SingletonHolder class
is not loaded until it is needed, and it won't be needed
until the first time someone calls getInstance.

It is thread-safe because class loading is itself
thread-safe. Only one thread will load SingletonHolder.
If twenty-seven threads all call getInstance at the same
time, SingletonHolder is still loaded and initialized only
once, and all those threads see the same INSTANCE value.

--
Eric....@sun.com

Arne Vajhøj

unread,
Jul 30, 2007, 9:39:02 PM7/30/07
to

I believe it is thread safe because class initialization is so and
it is lazy loaded because SingletonHolder will first be initialized
the first time Singleton.getInstance is called.

It is one of the weird approaches people take to avoid using
synchronized, which in most cases will work just fine.

Arne

David Gourley

unread,
Jul 31, 2007, 3:47:21 PM7/31/07
to
Arne Vajhøj wrote:
>
>
>
> I believe it is thread safe because class initialization is so and
> it is lazy loaded because SingletonHolder will first be initialized
> the first time Singleton.getInstance is called.
>
> It is one of the weird approaches people take to avoid using
> synchronized, which in most cases will work just fine.
>
> Arne

One thing I don't like about lazy intitialization is the risk of
intermittent StackOverflowExceptions for *complex* singleton classes....
(which I've seen occur a number of times).

Dave

Twisted

unread,
Jul 31, 2007, 4:03:40 PM7/31/07
to
On Jul 31, 3:47 pm, David Gourley <d...@NOSPAM.gourley.plus.com>
wrote:

> One thing I don't like about lazy intitialization is the risk of
> intermittent StackOverflowExceptions for *complex* singleton classes....
> (which I've seen occur a number of times).

I don't see why this would happen; the pattern doesn't produce a
deeply nested call chain unless all classloading does on that
implementation. In fact, the call chain is longer by as little as just
1 stack frame:

public class Singleton1 {
private static Singleton1 instance = null;
private Singleton1 () { ... }
public static Singleton1 getInstance () {
synchronized (Singleton1.class) {
if (instance == null) instance = new Singleton1();
return instance;
}
}
}

The ... is in Singleton1.Singleton1() called from
Singleton1.getInstance()

public class Singleton2 {
private static class SingletonHolder {
public static final Singleton2 instance = new Singleton2();
}
Singleton2 () { ... }
public static Singleton2 getInstance () { return
SingletonHolder.instance; }
}

The ... is in Singleton2.Singleton2() called from
SingletonHolder.<static initializer> called from
Singleton2.getInstance()

There may be a few more between getInstance and the static initializer
depending on how the class loading implementation you use works,
likely including a loadClass(), but if it's pathologically many the
class loading implementation you use ... well, to put it bluntly, it
fucking blows. It is likely to cause problems at any point in the code
that happens to trigger class loading, whether singleton-related or
not.

In particular, the complexity of the singleton class itself doesn't
contribute anything to the nesting depth of calls unless the class
loader is really brain-dead and does some sort of recursion instead of
iteration on its members. So if the maximum is, say, 32768 nested
method calls, you're no more likely to exceed that if Singleton2 has
dozens of fields and methods than if Singleton2 has only one field and
one method, assuming a sane classloader implementation.

David Gourley

unread,
Aug 1, 2007, 4:57:56 PM8/1/07
to
Twisted wrote:
> On Jul 31, 3:47 pm, David Gourley <d...@NOSPAM.gourley.plus.com>
> wrote:
>
>>One thing I don't like about lazy intitialization is the risk of
>>intermittent StackOverflowExceptions for *complex* singleton classes....
>>(which I've seen occur a number of times).
>
>
> I don't see why this would happen; the pattern doesn't produce a
> deeply nested call chain unless all classloading does on that
> implementation. In fact, the call chain is longer by as little as just
> 1 stack frame:

But the class loader gets called from the current context in the current
thread.

See attached program (a bit evil because I knocked it up fairly quickly):

class SingletonWrapper {
static private SingletonWrapper mSw = new SingletonWrapper();

private SingletonWrapper() {
throw new RuntimeException("Give me a stack trace");
}

static public SingletonWrapper getInstance() {
return mSw;
}
}
class ClassLoaderTest {

static public void main(String[] args) {
int recurseDepth = Integer.parseInt(args[0]);
recurse (0,recurseDepth);
}

static private void recurse (int currentDepth, int maxDepth) {
try {
if (currentDepth < maxDepth) {
recurse(currentDepth+1,maxDepth);
}
else
SingletonWrapper.getInstance();
}
catch (Exception e) {
e.printStackTrace();
}
}
}

(you pass in a parameter saying how deep you want recursion to be before
getInstance is called).

java ClassLoaderTest 5:

Exception in thread "main" java.lang.ExceptionInInitializerError
at ClassLoaderTest.recurse(ClassLoaderTest.java:25)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.main(ClassLoaderTest.java:16)
Caused by: java.lang.RuntimeException: Give me a stack trace
at SingletonWrapper.<init>(ClassLoaderTest.java:5)
at SingletonWrapper.<clinit>(ClassLoaderTest.java:2)
... 7 more

java ClassLoaderTest 10:

Exception in thread "main" java.lang.ExceptionInInitializerError
at ClassLoaderTest.recurse(ClassLoaderTest.java:25)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.recurse(ClassLoaderTest.java:22)
at ClassLoaderTest.main(ClassLoaderTest.java:16)
Caused by: java.lang.RuntimeException: Give me a stack trace
at SingletonWrapper.<init>(ClassLoaderTest.java:5)
at SingletonWrapper.<clinit>(ClassLoaderTest.java:2)
... 12 more

Now in my noddy example, there's not much on the stack frame. But I've
seen cases where this triggered OutOfMemory...

Dave

Twisted

unread,
Aug 1, 2007, 8:20:52 PM8/1/07
to
On Aug 1, 4:57 pm, David Gourley <d...@NOSPAM.gourley.plus.com> wrote:
> But the class loader gets called from the current context in the current
> thread.

I don't see this being unique to the situation of loading singletons.
It seems likely to be just as much (or little) trouble any time
classloading happens in mid-run.

David Gourley

unread,
Aug 2, 2007, 3:51:50 PM8/2/07
to

Agreed it can happen other times.

However (for whatever reason) I've seen it happen more frequently with
singletons - and invariably happening for the first time in production
(when events/user actions occur in a different order to during test)

Dave

Twisted

unread,
Aug 2, 2007, 4:56:31 PM8/2/07
to
On Aug 2, 3:51 pm, David Gourley <d...@NOSPAM.gourley.plus.com> wrote:
> Agreed it can happen other times.
>
> However (for whatever reason) I've seen it happen more frequently with
> singletons - and invariably happening for the first time in production
> (when events/user actions occur in a different order to during test)

How many call frames deep does Sun's classloader go ordinarily? Either
it's excessive, or the application was teetering on the brink of a
stack overflow anyway. Also, there's probably a -Xmx style VM
commandline arg to increase the max stack depth for such deployments.

David Gourley

unread,
Aug 2, 2007, 5:50:42 PM8/2/07
to
Twisted wrote:

> How many call frames deep does Sun's classloader go ordinarily? Either
> it's excessive, or the application was teetering on the brink of a
> stack overflow anyway. Also, there's probably a -Xmx style VM
> commandline arg to increase the max stack depth for such deployments.
>

The classloader isn't necessarily the problem... eventually the
singleton constructor gets called - the depth of the call stack under
*its* constructor could be the problem. Yes - increasing the stack size
fixes the problem: I'd just prefer not to find this out on a live
system with high availability requirements.

Since running into these problems I've steered clear of lazy
initialisation of complex singletons (I prefer to explicitly initialise
them up front and have deterministic behaviour).

Dave

Twisted

unread,
Aug 3, 2007, 7:11:19 AM8/3/07
to
On Aug 2, 5:50 pm, David Gourley <d...@NOSPAM.gourley.plus.com> wrote:
> The classloader isn't necessarily the problem... eventually the
> singleton constructor gets called - the depth of the call stack under
> *its* constructor could be the problem.

In this case, the classloading-based trick isn't the problem at all;
the design of the constructor is such that any lazy instantiation
whatsoever carries roughly the same risk, however its thread-safety is
achieved (or even if it isn't!). If there's no way to reduce deep call
chaining (e.g. by turning recursion into iteration) in that
constructor, you should use eager initialization in your main() method
or thereabouts.

Another trick of course is to actually spawn a new thread to do the
initialization:

public MySingleton () {
final Object lock = new Object();
new Thread(new Runnable() {
public void run () {
initialize(lock);
}
}).start();
synchronized (lock) {
lock.wait();
}
}

public void initialize (Object lock) {
...
synchronized (lock) {
lock.notify();
}
}

The new thread has its own call stack and the initialization code has
only the one parent stack frame, the run() method of the anonymous
inner class. This is equivalent to the initialize() code being in the
constructor and the constructor being directly invoked from main() via
"MySingleton.instance = new MySingleton();" or whatever.

The lock object is used here simply to make the constructor block
until construction is actually complete; the execution is supposed to
be effectively serial, as the thread is not actually for
parallelization but to get an empty new stack with plenty of room to
play around in more or less for free.

The thread creation is relatively expensive but only happens the once
given that the constructor is called only once (perhaps lazily).

0 new messages