Singleton pattern is one of the most commonly used design patterns, A friend who is familiar with the design pattern is familiar with the singleton pattern. In general, the books that introduce the singleton mode will mention Hungry man and Slacker type
These two implementations. But in addition to these two ways, This article also introduces several other ways to implement a single example, Let's have a look.

 

brief introduction

Singleton pattern is a common software design pattern, A class defined as a singleton object can only have one instance.


Many times, the whole system only needs to have one global object, This is good for us to coordinate the overall behavior of the system. For example, in a server program, The configuration information of the server is stored in a file, These configuration data are uniformly read by a single object, Then other objects in the service process obtain these configuration information through the singleton object. This approach simplifies configuration management in complex environments.

Basic realization ideas

Singleton pattern requires that a class can have a reference to a return object( Always the same) And a way to get the instance( Must be a static method, Usually usedgetInstance This name).

The implementation of a single example is mainly through the following two steps:

* Define the constructor of this class as a private method, In this way, the code elsewhere cannot instantiate the class's objects by calling its constructor, Only static methods provided by this class can get the unique instance of this class;
*
Provides a static method within this class, When we call this method, Return the reference if the reference held by the class is not empty, If the reference maintained by a class is empty, an instance of the class is created and the instance reference is given to the reference maintained by the class.
Matters needing attention


Singleton mode must be used carefully in multithreaded applications. If a unique instance has not been created, There are two threads calling the creation method at the same time, At the same time, they do not detect the existence of a unique instance, At the same time, an instance is created, So two instances are constructed, Thus, it violates the principle of instance uniqueness in singleton mode.
The solution to this problem is to provide a mutex for variables indicating whether the class has been instantiated( Although this will reduce efficiency).

Eight ways to write a single case model

1, Hungry man( static const)[ available]
public class Singleton { private final static Singleton INSTANCE = new
Singleton();private Singleton(){} public static Singleton getInstance(){ return
INSTANCE; } }
Advantage: This kind of writing is relatively simple, Instantiation is done when the class is loaded. Avoid thread synchronization problems.

shortcoming: Instantiation is done when the class is loaded, fall short ofLazy Loading Effect. If you have never used this instance from the beginning to the end, It will cause a waste of memory.

2, Hungry man( Static code block)[ available]
public class Singleton { private static Singleton instance; static { instance =
new Singleton(); } private Singleton() {} public static Singleton getInstance()
{return instance; } }
This way is similar to the above way, Just put the process of class instantiation in the static code block, Also when the class is loaded, Just execute the code in the static code block, Initializing an instance of a class. The advantages and disadvantages are the same as above.

3, Slacker type( Thread unsafe)[ Unavailable]
public class Singleton { private static Singleton singleton; private
Singleton() {}public static Singleton getInstance() { if (singleton == null) {
singleton= new Singleton(); } return singleton; } }
This kind of writing worksLazy Loading Effect, But it can only be used under single thread. If you are multithreaded, A thread has enteredif (singleton ==
null) Judgment block, We haven't got time to move on, Another thread also passed this judgment statement, Multiple instances will be generated. Therefore, this method cannot be used in multithreaded environment.

4, Slacker type( Thread safety, Synchronization method)[ Not recommended]
public class Singleton { private static Singleton singleton; private
Singleton() {}public static synchronized Singleton getInstance() { if
(singleton ==null) { singleton = new Singleton(); } return singleton; } }
Solve the thread unsafe problem of the third implementation method above, Just do a thread synchronization, So right.getInstance() Method to synchronize threads.


shortcoming: It's too inefficient, When each thread wants to get an instance of the class, implementgetInstance() Methods must be synchronized. In fact, this method can only execute the instantiation code once, Later, I want to get an instance of this class, directreturn All right.. Method synchronization efficiency is too low to be improved.

5, Slacker type( Thread safety, Sync code block)[ Unavailable]
public class Singleton { private static Singleton singleton; private
Singleton() {}public static Singleton getInstance() { if (singleton == null) {
synchronized (Singleton.class) { singleton = new Singleton(); } } return
singleton; } }

Because the synchronization efficiency of the fourth way is too low, So the synchronization method is abandoned, Generate instantiated code block synchronously instead. But this kind of synchronization does not work as thread synchronization. With the first3 The situations encountered by the implementation methods are the same, If a thread entersif
(singleton == null) Judgment block, We haven't got time to move on, Another thread also passed this judgment statement, Multiple instances will be generated.

6, duplication check[ Recommended use]
public class Singleton { private static volatile Singleton singleton; private
Singleton() {}public static Singleton getInstance() { if (singleton == null) {
synchronized (Singleton.class) { if (singleton == null) { singleton = new
Singleton(); } } }return singleton; } }
Double-Check Concepts are familiar to multithreaded developers, As shown in the code, We did it twiceif (singleton ==
null) inspect, This ensures thread safety. such, Instantiation code is only executed once, When I visit again later, judgeif (singleton ==
null), directreturn Instanced object.

Advantage: Thread safety; Delayed loading; Higher efficiency.

7, Static inner class[ Recommended use]
public class Singleton { private Singleton() {} private static class
SingletonInstance {private static final Singleton INSTANCE = new Singleton(); }
public static Singleton getInstance() { return SingletonInstance.INSTANCE; } }

This is similar to the mechanism adopted by the starved Han style, But it's different. Both of them adopt the mechanism of class loading to ensure that there is only one thread when initializing the instance. Different places in the starving Han style way are as long asSingleton Class will be instantiated when loaded, No,Lazy-Loading Role, The static inner class mode isSingleton Class is not instantiated immediately when it is loaded, But when you need to instantiate, callgetInstance Method, LoadingSingletonInstance class, Thereby completingSingleton Instantiation.

Class static properties are initialized only when the class is first loaded, So it's here,JVM It helps us to ensure thread safety, When class initializes, Other threads are not accessible.

Advantage: Avoid thread insecurity, Delayed loading, Efficient.

8, enumeration[ Recommended use]
public enum Singleton { INSTANCE; public void whateverMethod() { } }

With the helpJDK1.5 Enumeration added in to implement singleton mode. Not only can multithreading synchronization be avoided, It also prevents deserialization from recreating new objects. Maybe it's because enumerations areJDK1.5 Medium added, So in the actual project development, It's rarely written like this.

Advantage

Only one object of this class exists in system memory, Save system resources, For some objects that need to be destroyed frequently, Using singleton mode can improve system performance.

shortcoming

When you want to instantiate a singleton class, You must remember to use the corresponding method to get the object, Instead of usingnew, May cause trouble to other developers, Especially when you can't see the source code.

Suitable occasion

* Objects that need to be created and destroyed frequently;
* Too much time or resources to create objects, But often used objects;
* Tool class object;
* Objects that frequently access databases or files.