I’ve been finding many thread-safety issues in the GlassFish source
base in the past several months, mostly in the admin code. Many of them involve singleton objects, typically
obtained via a getInstance() method.
If loading of the class implies immediate use of its singleton instance, and it doesn’t
require any arguments to be created, the most efficient (and thread-safe) approach is simply to initialize the
instance in a static variable as follows:
// Listing 1
public class Resource {
private static final Resource _Instance = new Resource();
public Resource getInstance() {
return _Instance;
}
For more complex cases, I’ve begun to consider using the "Holder" idiom as
described on page 348 of Java Concurrency in Practice
. This idiom can be helpful when it is desirable to perform lazy initialization
of a resource that might or might not be used. Java Concurrency provides the following code example:
// Listing 2 (prefer Listing 1 above if appropriate)
public class ResourceFactory {
private static class ResourceHolder {
public static Resource resource = new Resource();
}
public static Resource getResource() {
return ResourceHolder.resource;
}
}
The above idiom has the desirable property of avoiding initialization of a Resource until
it is actually needed; the Java Virtual Machine won’t load the ResourceHolder class
until it is actually accessed. Because static variables are always guaranteed to be initialized in a thread-safe
manner, thread safety is not an issue. This approach might be useful in a class that has multiple objects to initialize
as needed and/or if there is a runtime decision to be made based on parameters.
The
solution in Listing 2 is good —but
the implementation has several questionable issues:
- The class ResourceHolder solves one thread safety issue
with a dubious declaration, namely that the variable resource is not final,
and therefore could be changed to refer to a different instance of Resource—a
thread safety issue.
- The class ResourceHolder is non-final and it can be constructed as well. There
is no legitimate argument for
ResourceHolder to ever be a superclass, or to allow an instance of it to be constructed.
- It's dubious that a Factory class (ResourceFactory) should be non-final,
and thus able to be subclassed. It’s also dubious to allow an instance of it to be constructed.
The example is self-documenting and unambiguous when improved
as follows (changes in red):
// Listing 3
public final class ResourceFactory {
private ResourceFactory() {/*disallow instantiation*/}
private static final class ResourceHolder {
private ResourceHolder() {/*disallow instantiation*/}
public static final Resource resource = new Resource();
}
public static Resource getResource() {
return ResourceHolder.resource;
}
}
Posted by llc
Trackback URL: http://blogs.sun.com/lchambers/entry/h1_an_improvement_on_the