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 Han style and Slovenly
These two implementations . But there are 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 , Commonly used getInstance 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 unique instances 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 it will reduce efficiency ).

Eight ways to write a single case model

1, Hungry Han style ( 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 of Lazy Loading Effect of . If you have never used this instance from the beginning to the end , It will cause a waste of memory .

2, Hungry Han style ( 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, Slovenly ( Thread unsafe )[ Not available ]
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 works Lazy Loading Effect of , But it can only be used under single thread . If you are multithreaded , A thread has entered if (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, Slovenly ( 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 that's right getInstance() Method to synchronize threads .


shortcoming : It's too inefficient , When each thread wants to get an instance of the class , implement getInstance() 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 , direct return Just do it . Method synchronization efficiency is too low to be improved .

5, Slovenly ( Thread safety , Sync code block )[ Not available ]
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 . Follow the 3 The situations encountered by the implementation methods are the same , If a thread enters if
(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 ]
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 twice if (singleton ==
null) inspect , This ensures thread safety . such , Instantiation code is only executed once , When I visit again later , judge if (singleton ==
null), direct return Instanced object .

advantage : Thread safety ; Delay loading ; High efficiency .

7, Static inner class [ Recommended ]
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 as Singleton Class will be instantiated when loaded , No, Lazy-Loading The role of , The static inner class mode is Singleton Class is not instantiated immediately when it is loaded , But when you need to instantiate , call getInstance method , Will be loaded SingletonInstance class , To complete Singleton Instantiation of .

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 , Delay loading , efficient .

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

With the help of JDK1.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 are JDK1.5 Add only in , 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 using new, May cause trouble to other developers , Especially when you can't see the source code .

Applicable occasions

* 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 .