This is just a summary of alternatives to the double-checked locking pattern, which has been shown to have potential problems. The alternatives are taken from a CERT wiki article. The motivations for the pattern come from three concerns:
- avoid constructing an object that is expensive to construct, unless-until it is needed
- avoid more than one instantiation of that object, and
- avoid the overhead of synchronization for the more common case of fetching the object.
The simplest way to correct some legacy in-place double-check locking code is to simply declare the object in question as volatile - however, this only works with the newer Java memory model (since JDK 1.4), and (in my opinion) leaves some unnecessary code cruft in place (i.e., see below for more elegant alternatives):
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized (this) {
if (helper == null) {
helper = new Helper(); // If the helper is null, create a new instance
}
}
}
return helper; // If helper is non-null, return its instance
}
}
Static initialization partially addresses the problem - it guarantees that the object is constructed at-most-once, but foregoes the lazy initialization - i.e, the object is constructed exactly once, whether it's needed or not:
class Foo {
private static final Helper helper = new Helper();
public static Helper getHelper() {
return helper;
}
}
Initialize-on-demand addresses all three concerns:
class Foo {
private static class Holder {
static Helper helper = new Helper();
}
public static Helper getInstance() {
return Holder.helper;
}
}
With an immutable object, the Java memory model problems are also addressed by virtue of using final fields:
public final class Helper {
private final int n;
public Helper(int n) {
this.n = n;
}
// Other fields and methods, all fields are final. With this in place, the double-checked locking pattern is perfectly fine.
}
Finally, note that a standard otherwise-broken double-checked locking pattern is perfectly fine when initializing 32-bit primitives.
No comments:
Post a Comment