Singleton < Javapedia < TWiki
|
TWiki . Javapedia . Singleton
|
Singleton
- A singleton is, in a nutshell, a class which only permits one instance of itself to be instantiated.
- Inherently, java applications execute in a complex classloader environment which makes it impossible to truly guarantee that there will only be one instance of the class per java process. Java singletons can still be useful, but bear that caveat in mind, always.
- At best you can guarantee one instance per classloader. Some contexts, for example servlet engines and J2EE application servers, should routinely expect to use more than one classloader per java process (typically each webapp in a servlet engine has its own classloader) or even more than one classloader per webapp (in the case of load-balancing across processes or across machines).
- The classic example of a good reason to use a singleton is as a factory that hides an object pool. The classic mistake is to use a singleton to implement global variables.
- Typically a singleton is accomplished by declaring the only constructor private, so it can't be invoked from outside the class, and then having an instance variable to hold the single instance reference, and a synchronized getInstance() method that returns the reference, instantiating the single instance and setting the instance variable if necessary .
- Sometimes people use a static initializer block to implement a singleton. This is generally considered inferior to using a synchronized getInstance() method, though some developers disagree (obviously, I think they're wrong). Static initializer blocks have their initial value defined at compile time; static items cannot be used to implement an interface; static initializer singletons generally mean the instance reference is being accessed directly, not via a getter, and hence they're harder to change later, if, for example you decide the single instance object needs to be replaced with a pool. The synchronized method has a slight performance penalty, but not nearly as much as people seem to think.
- Double-checked locking is broken, broken, broken. Double-checked locking is the dodge of having an unsynchronized getInstance() accessor with a synchronized block around the chunk of code inside getInstance() that does the actual instantiation. Problem is, there's no guarantee that the synchronized block will happen in any sequence related to the rest of the method, so it's possible for the method to return a reference to a half-instantiated singleton instance. Don't take my word for it, read:
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Or even:
http://www.google.com/search?q=double+checked+locking+is+broken&ie=utf-8&oe=utf-8&rls=Swiftfox:en-US:unofficial&client=firefox-a
- As of Java 1.6, double-checked locking is now non-broken, if you designate the instance variable as volatile. However volatile is almost as expensive as synchronized in 1,6, anyway.
- In any event, double-checked locking is being needlessly clever to solve a problem that doesn't need to be solved; it's a case of premature optimization.
- Also see Josh Block's SingletonHolder? pattern, essentially the instance variable is, instead of a reference to the singleton class, a reference to a wrapper class.
- Finally, the example below breaks most of these rules.
/**
* A class of which at most one instance
* can exist per VM.
*
* Use Singleton.getInstance() to access this
* instance.
*/
public class Singleton {
/**
* The constructor could be made private
* to prevent others from instantiating this class.
* But this would also make it impossible to
* create instances of Singleton subclasses.
*/
protected Singleton() {
// ...
}
/**
* A handle to the unique Singleton instance.
*/
static private Singleton instance = null;
/**
* @return The unique instance of this class.
*/
static public Singleton getInstance() {
if(null == instance) {
instance = new Singleton();
}
return instance;
}
/**
* This version of the method will assure that one and only one
* instance is created in a multithreaded environment.
*
* @return The unique instance of this class
*/
static public Singleton getThreadSafeInstance() {
if (null == instance) {
synchronized(Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
// ...additional methods omitted...
}
Also See
Articles
Discussion about Singleton
It is not possible in Java to have "A class of which at most one instance can exist per VM." The best that you can do is one instance per classloader. This has particularly serious effects on applets. -- DougPardee 12-Jun-03
The implementation above incorporates a classic mistake, because it is not thread-safe. The everyday type of Singleton can be implemented much more easily in Java than by trying to reproduce the C++ code from the GoF book:
public class Singleton {
public static final instance = new Singleton();
// constructor and instance methods
}
There is no need for a "getter" because we can define the static attribute to be final. There is no need for the fancy (but not thread-safe) logic to determine if an instance already exists and create one if not, because Java always uses "lazy initialization". -- DougPardee 12-Jun-03
The additional version of the getThreadSafeInstance method included above shows a way to ensure creation of a single instance with minimal synchronization. This helps in situations where the instance should not be created until it is explicitely requested (although the article above about double checked locking casts some doubt on its effectiveness) -- Grandin Hammell 22-Jul-04
----- Revision r13 - 14 Feb 2007 - 10:38:26 - Main.puff
|