‘Singleton’ is a fancy word for ‘global variable.’ The intent of Singleton: Ensure a class only has one instance, and provide a global point of access to it. - GOF All singleton implementations offer NO public constructor but only private constructor to enforce non-instantiability. In Java, however, because a private constructor can still be accessed through a backdoor of using reflection, you want to add extra check in the private constructor to guard against reflection vulnerability (see examples below). approach #1Is this approach thread-safe? Yes. Prior to Java 1.5 release, using initialization of a static final member field, there are primarily two ways of making a class singleton. One way is to make this static final member public and be initialized when referenced: public class Singleton{ The Singleton object is not created until Singleton.INSTANCE is referenced. [1] Static variable INSTANCE will be initialized when Singleton.INSTANCE is referenced (requested). [2] The extra check on whether INSTANCE is null or not in the private constructor is to guard against reflection attack which is how multiple instances may be instantiated is now prevented. approach #2Is this approach thread-safe? Yes. Another way is to make this static final member private with a public static factory-method (getInstance()) to return the sole singleton instance: public class Singleton{ The Singleton object is also not created until a call is made to the static getInstance() method to reference the static member field INSTANCE. One of the advantages of this factory-method approach over the first approach is that you can later change the implementation of getInstance() without clients needing to change the interface of calling it. For example, instead of returning a sole instance per classloader, your can extend to make getInstance() to return a sole instance per thread. approach #3Is this approach thread-safe? Yes. Both approach #1 and #2 initialize a static field to ensure that the Singleton object is not created until Singleton.INSTANCE is referenced or when a call is made to the static getInstance() method. This is a good approach because such Singleton implementations are thread-safe when it comes to getting a reference to the Singleton instance. Otherwise, should you not initialize the static member field via declaration, you'll have to assure thread-safe via synchronization as in this approach: public class Singleton{ Synchronization is costly. Although Double Checked Locking idiom was mentioned to make above costly synchronized block smaller to reduce overhead in a multi-threaded environment, but the double Checked Locking is not a safe programming construct due to the current Java memory model making it an anti-pattern. approach #4Is this approach thread-safe? Yes. Both serializable and deserializable? Yes. A forth and better way of implementing Singleton is to use a single-element Enum type (available in Java 1.6+). Enum constants (e.g. INSTANCE) are implicitly static and final so you can not change INSTANCE value once created. The constructor of enum in java must be private to hide it. Utilize it to wrap around the singleton object you'd like to assure singleton and return it. public enum Singleton{ // 1 [1] enum is automatically Serializable according to its javadoc. [2] Initialize the connection when enum (Singleton.INSTANCE) is referenced for the first time. To get a reference to the singleton object, use Singleton.getInstance() or Singleton.INSTANCE. To get the connection, do Singleton.INSTANCE.getConnection(). This single-element Enum provides an guarantee against multiple instantiation, and hold up pretty well in the face of sophisticated serialization or reflection attacks, making it the recommended approach of all approaches. serializable singletonWithout extra consideration, most of the above approaches serializable does not make the deserialization back to a Singleton unless you add readResolve() implementation (more details see my Java Serialization post) to your serializable class so that when Singleton is deserialized, the returned object is a guaranteed singleton: public class Singleton implements Serializable{ [1] The readResolve method is called when ObjectInputStream has read an object from the stream and is preparing to return it to the caller. It should not be explicitly called other than by the deserialization runtime. The "enum approach" does comes an guarantee against multiple instantiation without needing extra code, making it serializable singleton by default for free. discussionSome consider Singleton an anti-pattern because it couples your code with specific implementation. Here's a scenario: Whenever a client retrieves a singleton's instance, that client becomes undesirably coupled with the fact that its supplier is a specific type of singleton. For example, in the following code snippet, the Client can no longer easily 'deploy' by swapping in a different kind of Deployer because the principle of "programming to an interface, not an implementation" is violated. public class Client { Therefore, do not over use Singleton, consider to use Singleton only when
summaryAccept synchronization, use a static field, or use enum to make Singleton thread-safe. Get away from Double Checked Locking idiom which is an antipattern. Do not overuse Singleton. references
0 Comments
Leave a Reply. |
Categories
All
Archives
May 2020
|