We need to make sure that threads calling the getSingletonObject() method don't cause problems, so it's advisable to mark the method as synchronized. This prevents two threads from calling the getSingletonObject() method at the same time. If one thread entered the method just after the other, you could end up calling the SingletonObject constructor twice and returning different values. To change the method, just add the synchronized keyword as follows to the method declaration :-
public static synchronized
SingletonObject getSingletonObject()
Are we finished yet?
There, finished. A singleton object that guarantees one instance of the class, and never more than one. Right? Well.... not quite. Where there's a will, there's a way - it is still possible to evade all our defensive programming and create more than one instance of the singleton class defined above. Here's where most articles on singletons fall down, because they forget about cloning. Examine the following code snippet, which clones a singleton object.
public class Clone
{
public static void main(String args[])
throws Exception
{
// Get a singleton
SingletonObject obj =
SingletonObject.getSingletonObject();
// Buahahaha. Let's clone the object
SingletonObject clone =
(SingletonObject) obj.clone();
}
}
Okay, we're cheating a little here. There isn't a clone() method defined in SingletonObject, but there is in the java.lang.Object class which it is inherited from. By default, the clone() method is marked as protected, but if your SingletonObject extends another class that does support cloning, it is possible to violate the design principles of the singleton. So, to be absolutely positively 100% certain that a singleton really is a singleton, we must add a clone() method of our own, and throw a CloneNotSupportedException if anyone dares try!
Here's the final source code for a SingletonObject, which you can use as a template for your own singletons.
public class SingletonObject
{
private SingletonObject()
{
// no code req'd
}
public static SingletonObject getSingletonObject()
{
if (ref == null)
// it's ok, we can call this constructor
ref = new SingletonObject();
return ref;
}
public Object clone()
throws CloneNotSupportedException
{
throw new CloneNotSupportedException();
// that'll teach 'em
}
private static SingletonObject ref;
}
No comments:
Post a Comment