The singleton mode has always been known, but it feels cloudy and foggy. This time, I will summarize the various writing methods in detail. It is a summary.
The singleton pattern is mainly used to safely publish objects, which cannot be arbitrarily changed by other objects, so the constructor is required to be private, that is, the object can be instantiated within the class.
1. Not thread-safe lazy mode, create an instance when it is used for the first time
/** * Lazy mode * The singleton instance is created when it is used for the first time */ @NotThreadSafe public class SingletonExample1 { // private constructor private SingletonExample1() { } // singleton object private static SingletonExample1 instance = null; // static factory method public static SingletonExample1 getInstance() { if (instance == null) {//Obviously there will be a problem here when it is concurrent, resulting in not being a singleton instance = new SingletonExample1(); } return instance; } }
2 Hungry mode Singleton instance is created during class loading, and there are many operations during class loading, which may waste resources
/** * Hungry mode * Singleton instances are created during class loading, and there are many operations during class loading, which may waste resources */ @ThreadSafe public class SingletonExample2 { // private constructor private SingletonExample2() { } // singleton object private static SingletonExample2 instance = new SingletonExample2(); // static factory method public static SingletonExample2 getInstance() { return instance; } }
3 Thread-safe lazy mode
/** * Lazy mode * The singleton instance is created when it is used for the first time */ @ThreadSafe @NotRecommend public class SingletonExample3 { // private constructor private SingletonExample3() { } // singleton object private static SingletonExample3 instance = null; // Static factory method locking here will reduce concurrency. Many smart people later came up with DCL public static synchronized SingletonExample3 getInstance() { if (instance == null) { instance = new SingletonExample3(); } return instance; } }
4 DCL's Lazy Mode
/** * Lazy mode - "Double synchronization lock singleton mode * The singleton instance is created when it is used for the first time */ @NotThreadSafe public class SingletonExample4 { // private constructor private SingletonExample4() { } // 1. memory = allocate() allocates the memory space of the object // 2. ctorInstance() initializes the object // 3. instance = memory Set instance to point to the memory just allocated // JVM and cpu optimization, instruction rearrangement occurs // 1. memory = allocate() allocates the memory space of the object // 3. instance = memory Set instance to point to the memory just allocated // 2. ctorInstance() initializes the object // singleton object private static SingletonExample4 instance = null; // static factory method public static SingletonExample4 getInstance() { if (instance == null) { // double detection mechanism // B thread finds the object is null here synchronized (SingletonExample4.class) { // synchronized lock if (instance == null) { instance = new SingletonExample4(); // Instruction remakes A thread - 3 allocates memory first } } } return instance; } }
5 Implementing DCL with volatile
/** * Lazy mode - "Double synchronization lock singleton mode * The singleton instance is created when it is used for the first time */ @ThreadSafe public class SingletonExample5 { // private constructor private SingletonExample5() { } // 1. memory = allocate() allocates the memory space of the object // 2. ctorInstance() initializes the object // 3. instance = memory Set instance to point to the memory just allocated // singleton object volatile + double detection mechanism -> prohibit instruction rearrangement private volatile static SingletonExample5 instance = null; // static factory method public static SingletonExample5 getInstance() { if (instance == null) { // double detection mechanism // B synchronized (SingletonExample5.class) { // synchronized lock if (instance == null) { instance = new SingletonExample5(); // A - 3 } } } return instance; } }
6 Another Hungry Man Mode
/** * Hungry mode * Singleton instance is created at class loading */ @ThreadSafe public class SingletonExample6 { // private constructor private SingletonExample6() { } // singleton object private static SingletonExample6 instance = null; // must pay attention to the order static { instance = new SingletonExample6(); } // static factory method public static SingletonExample6 getInstance() { return instance; } public static void main(String[] args) { System.out.println(getInstance().hashCode()); System.out.println(getInstance().hashCode()); } }
7 The simplest singleton implementation Enumeration // I will look at this in detail and complete it. I rarely use enumerations, and the code is still written less.
/** * Enumeration mode: safest */ @ThreadSafe @Recommend public class SingletonExample7 { // private constructor private SingletonExample7() { } public static SingletonExample7 getInstance() { return Singleton.INSTANCE.getInstance(); } private enum Singleton { INSTANCE; private SingletonExample7 singleton; // JVM guarantees that this method is called absolutely only once Singleton() { singleton = new SingletonExample7(); } public SingletonExample7 getInstance() { return singleton; } } }