Shalloway and Trott's solution to double checked locking?

  • Thread starter Cephalobus_alienus
  • Start date
C

Cephalobus_alienus

Shalloway and Trott, in their book Design Patterns
Explained, 2nd edition, published what they claim to
be a fix for the broken Double-Checked Locking Pattern.

Would the following truly be a valid means of
implementing a thread-safe singleton?

--- Begin quote from Design Patterns Explained ---
When the Double-Checked Locking pattern was converted
from C++ to Java, it was soon discovered that it did
not work for Java.[4] The reason is that the Java
compiler, in its optimization efforts, may return the
reference to an object from a constructor before the
constructor is through instantiating the object. Thus,
dosync may complete before USTax is actually completely
built. This may cause a problem. Also an optimizing
compiler may "notice" that there is "no way" for the
"instance" member to change state between the two "if"
statements, and optimize the second one out. You can
avoid this problem in C# by using the keyword volatile.

[4] See the book's Web site at http://www.netobjectives.com/dpexplained
for more information on this.

A Solution for Java

It is not all that hard to fix this-not that I figured
it out on my own. One solution is to take advantage of
the class loader, as shown in Example 21-4.

Example 21-4. Java Code Fragment: Instantiation Only
public class USTax extends Tax {
private static class Instance {
static final Tax instance= new USTax();
}
private static USTax instance;
private USTax() { }
public static Tax getInstance() {
return Instance.instance;
}
}

This works because the inner class (Instance) will get
loaded only once; therefore, only one USTax object is
built.
--- End quote from Design Patterns Explained ---

Thanks for your comments,
Jerry
 
M

Mark Thornton

Shalloway and Trott, in their book Design Patterns
Explained, 2nd edition, published what they claim to
be a fix for the broken Double-Checked Locking Pattern.

Would the following truly be a valid means of
implementing a thread-safe singleton?

Yes it does work because the JVM implicitly synchronizes the class
loading. Note also that double checked locking is also broken for C++ on
machines with very weak memory models. On these (multi-processor)
machines the CPUs can rearrange actions in the same manner as some Java
compilers unless appropriate synchronization is used. In this case the
language in use doesn't manner; unless you use synchronization (explicit
or implicit) double checked locking can fail.

Mark Thornton
--- Begin quote from Design Patterns Explained ---
When the Double-Checked Locking pattern was converted
from C++ to Java, it was soon discovered that it did
not work for Java.[4] The reason is that the Java
compiler, in its optimization efforts, may return the
reference to an object from a constructor before the
constructor is through instantiating the object. Thus,
dosync may complete before USTax is actually completely
built. This may cause a problem. Also an optimizing
compiler may "notice" that there is "no way" for the
"instance" member to change state between the two "if"
statements, and optimize the second one out. You can
avoid this problem in C# by using the keyword volatile.

[4] See the book's Web site at http://www.netobjectives.com/dpexplained
for more information on this.

A Solution for Java

It is not all that hard to fix this-not that I figured
it out on my own. One solution is to take advantage of
the class loader, as shown in Example 21-4.

Example 21-4. Java Code Fragment: Instantiation Only
public class USTax extends Tax {
private static class Instance {
static final Tax instance= new USTax();
}
private static USTax instance;
private USTax() { }
public static Tax getInstance() {
return Instance.instance;
}
}

This works because the inner class (Instance) will get
loaded only once; therefore, only one USTax object is
built.
--- End quote from Design Patterns Explained ---

Thanks for your comments,
Jerry
 
R

Roedy Green

This works because the inner class (Instance) will get
loaded only once; therefore, only one USTax object is
built.
--- End quote from Design Patterns Explained ---

Thanks for your comments,

The biggest catch is there is about 3K overhead for the solution. The
nice part is the solution is simple enough to write off the top of
your head.
 
J

John C. Bollinger

Shalloway and Trott, in their book Design Patterns
Explained, 2nd edition, published what they claim to
be a fix for the broken Double-Checked Locking Pattern.

Would the following truly be a valid means of
implementing a thread-safe singleton?
[...]

Example 21-4. Java Code Fragment: Instantiation Only
public class USTax extends Tax {
private static class Instance {
static final Tax instance= new USTax();
}
private static USTax instance;
private USTax() { }
public static Tax getInstance() {
return Instance.instance;
}
}

It is a correct implementation of a thread-safe singleton. It is overly
complicated, I think, in that this would be sufficient:

public class USTax extends Tax {
private static Tax instance = new USTax();
private USTax() { }
public static Tax getInstance() {
return instance;
}
}

I wouldn't exactly call either one a "solution to double-checked
locking", however, for they doesn't implement any variation on DCL. The
point of the intermediary class may be to afford lazy initialization of
the USTax instance, which is a purported benefit of DCL, but you may get
that from your VM anyway with my simplified approach. Even if not, lazy
initialization of this variable is unlikely to gain you anything worth
having unless the initialization is very expensive and there is a good
chance of the instance not being used.
 
R

Ross Bamford

Shalloway and Trott, in their book Design Patterns
Explained, 2nd edition, published what they claim to
be a fix for the broken Double-Checked Locking Pattern.

Would the following truly be a valid means of
implementing a thread-safe singleton?

--- Begin quote from Design Patterns Explained ---
[ ... ]

Example 21-4. Java Code Fragment: Instantiation Only
public class USTax extends Tax {
private static class Instance {
static final Tax instance= new USTax();
}
private static USTax instance;
private USTax() { }
public static Tax getInstance() {
return Instance.instance;
}
}

This works because the inner class (Instance) will get
loaded only once; therefore, only one USTax object is
built.
--- End quote from Design Patterns Explained ---

Aside from being overly complicated (see later messages on this thread), I
wonder if it even works, given that the static nested (not inner) class
isn't really all that tightly linked to the outer class. Perhaps if it was
an inner class (not static) this would be different but in any case it's
made even more complicated by the possibly variant timing of the <clinit>
invocations. I think (I've not looked this up specifically) that the
<clinit> would be unlikely to run on the nested class (executing the new
USTax() call) until the first time you called getInstance().

Even allowing for that, I'd guess optimization could have a field day with
this as written?
 
M

Mark Thornton

Ross said:
Shalloway and Trott, in their book Design Patterns
Explained, 2nd edition, published what they claim to
be a fix for the broken Double-Checked Locking Pattern.

Would the following truly be a valid means of
implementing a thread-safe singleton?

--- Begin quote from Design Patterns Explained ---
[ ... ]

Example 21-4. Java Code Fragment: Instantiation Only
public class USTax extends Tax {
private static class Instance {
static final Tax instance= new USTax();
}
private static USTax instance;
private USTax() { }
public static Tax getInstance() {
return Instance.instance;
}
}

This works because the inner class (Instance) will get
loaded only once; therefore, only one USTax object is
built.
--- End quote from Design Patterns Explained ---


Aside from being overly complicated (see later messages on this thread),
I wonder if it even works, given that the static nested (not inner)
class isn't really all that tightly linked to the outer class. Perhaps
if it was an inner class (not static) this would be different but in
any case it's made even more complicated by the possibly variant timing
of the <clinit> invocations. I think (I've not looked this up
specifically) that the <clinit> would be unlikely to run on the nested
class (executing the new USTax() call) until the first time you called
getInstance().

Even allowing for that, I'd guess optimization could have a field day
with this as written?

No. There are special rules which mean that class loading and
initialization is effectively synchronized.

Mark Thornton
 
R

Ross Bamford

Shalloway and Trott, in their book Design Patterns
Explained, 2nd edition, published what they claim to
be a fix for the broken Double-Checked Locking Pattern.

Would the following truly be a valid means of
implementing a thread-safe singleton?

--- Begin quote from Design Patterns Explained ---
[ ... ]

Example 21-4. Java Code Fragment: Instantiation Only
public class USTax extends Tax {
private static class Instance {
static final Tax instance= new USTax();
}
private static USTax instance;
private USTax() { }
public static Tax getInstance() {
return Instance.instance;
}
}

This works because the inner class (Instance) will get
loaded only once; therefore, only one USTax object is
built.
--- End quote from Design Patterns Explained ---

Aside from being overly complicated (see later messages on this thread),
I wonder if it even works, given that the static nested (not inner)
class isn't really all that tightly linked to the outer class. Perhaps
if it was an inner class (not static) this would be different but in any
case it's made even more complicated by the possibly variant timing of
the <clinit> invocations. I think (I've not looked this up specifically)
that the <clinit> would be unlikely to run on the nested class
(executing the new USTax() call) until the first time you called
getInstance().

Even allowing for that, I'd guess optimization could have a field day
with this as written?

Thinking more about it, I realise now that it doesn't actually matter (as
long as the rest of the class is well behaved), since it's still
guaranteed to have run (and done the init) before you get the instance...

In any event, I still agree with John Bollinger's view that it's
unnecessarily complicated...
 
R

Ross Bamford

Ross said:
Shalloway and Trott, in their book Design Patterns
Explained, 2nd edition, published what they claim to
be a fix for the broken Double-Checked Locking Pattern.

Would the following truly be a valid means of
implementing a thread-safe singleton?

--- Begin quote from Design Patterns Explained ---
[ ... ]

Example 21-4. Java Code Fragment: Instantiation Only
public class USTax extends Tax {
private static class Instance {
static final Tax instance= new USTax();
}
private static USTax instance;
private USTax() { }
public static Tax getInstance() {
return Instance.instance;
}
}

This works because the inner class (Instance) will get
loaded only once; therefore, only one USTax object is
built.
--- End quote from Design Patterns Explained ---
Aside from being overly complicated (see later messages on this
thread), I wonder if it even works, given that the static nested (not
inner) class isn't really all that tightly linked to the outer class.
Perhaps if it was an inner class (not static) this would be different
but in any case it's made even more complicated by the possibly
variant timing of the <clinit> invocations. I think (I've not looked
this up specifically) that the <clinit> would be unlikely to run on
the nested class (executing the new USTax() call) until the first time
you called getInstance().
Even allowing for that, I'd guess optimization could have a field day
with this as written?

No. There are special rules which mean that class loading and
initialization is effectively synchronized.

Mark Thornton


That's true, but what I was looking at was that the nested class isn't
referenced anywhere in the outer's initialization, and I don't think that
just being a nested class gets it automatically initialized, until it's
actually used (given that the nested is really no different from an outer)?

However, I saw after my original post that it's irrelevant anyway, since
the (static) getInstance() method would of course cause that to happen on
the first call. But aren't we then back to where we started, since the
loading and init isn't necessarily happening in sequence (or even closely
timed).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top