An introduction to a single case pattern and its usage scenarios
The singleton pattern is the most widely used pattern, and one of the first design patterns I've ever known, and I'll use it as a singleton when I run into the code for creating instances like: getinstance () before delving into the singleton pattern. In fact, often used picture loading framework Imageloader instance creation is the use of a singleton mode, because this imageloader contains a thread pool, cache system, network requests, very consumption of resources, should not create multiple objects, this time need to use a singleton mode.
The creation code for Imageloader is as follows:
Imageloader.getinstance ();//Create a global instance in your own application.....//getinstance () Implementation of the source code Public StaticImageloadergetinstance() {if(Instance = =NULL) {//double-check DCL single-case modeClass var0 = Imageloader.class;synchronized(Imageloader.class) {//Synchronous code block if(Instance = =NULL) {instance =NewImageloader ();//Create a new instance} } }returnInstance//Returns an instance}
Therefore, when we create an object that consumes too much resources, we can consider using singleton mode.
The structure diagram of the two singleton patterns and the key points of the creation?
The singleton pattern is defined as it should guarantee that there is only one instance of a class, and that the class must provide a global access point to the class. As the structure of the singleton pattern:
There are several key points to implementing the Singleton pattern:
(1) Its construction function is not open to the outside, generally private;
(2) Returning a singleton class object through a static method or enumeration;
(3) Ensure that the object of the Singleton class has only one, especially to pay attention to the multi-threading scene;
(4) Ensure that the Singleton class object is not re-created when deserializing;
By privatizing the constructor of a singleton class, the client cannot manually construct an object of the Singleton class by using new. The Singleton class exposes a public static method, and the client calls the static method to get the unique instance of the Singleton class. When you get this singleton class, you need to make sure that the process is thread-safe.
Seven ways of realizing three single-case patterns
(1) Lazy type (thread unsafe)
//lazy Type singleton class. Instantiate yourself class Singleton {//private constructors private singleton () {} // private static variable private static Singleton Single =null ; //exposed public static method public static Singleton getinstance () {if (single = null ) {single = new Singleton (); } return single; } }
Lazy (thread insecure) singleton mode is divided into three parts: private construction method, private global static variable, public static method.
One of the important functions of the static modifier is the Statics keyword, and we know that in a program, any variable or code is automatically allocated by the system at compile time to store the memory, and so-called static refers to the memory allocated after compilation will persist until the program exits memory to release this space, As a result, instances of singleton classes are not reclaimed by the system once they are created, unless they are manually set to NULL.
The disadvantage of this approach is that there is a problem with thread insecurity, and the solution is to use the Synchronized keyword, which is the second way to approach the singleton pattern.
(2) Lazy (thread-safe)
publicclass Singleton { //私有的静态变量 privatestatic Singleton instance; //私有的构造方法 privateSingleton (){}; //公有的同步静态方法 publicstaticgetInstance() { ifnull) { new Singleton(); } return instance; } }
The getinstance () method of this singleton implementation adds the Synchronized keyword, which tells the Java (JVM) getinstance to be a synchronous method.
Synchronization means that when two concurrent threads access this synchronized synchronization method in the same class, only one thread can be executed at a time, and the other thread must wait for the current thread to execute before executing, so the synchronization method makes the thread safe, guaranteeing that only one instance of the singleton is available.
However, its disadvantage is that each call to getinstance () is synchronized, causing unnecessary synchronization overhead. This mode is generally not recommended for use.
(3) A Hungry man mode (thread safe)
The code is implemented as follows:
//饿汉式单例类.在类初始化时,已经自行实例化 publicclass Singleton { //static修饰的静态变量在内存中一旦创建,便永久存在 privatestaticnew Singleton(); privateSingleton (){} publicstaticgetInstance() { return instance; }
A hungry man in the creation of a class at the same time has created a static object for the system to use, no longer change, so it is inherently thread-safe. where Instance=new Singleton () can be written as:
static { new Singleton(); }
A hungry man is a variant of the single-case pattern, but also based on the classloder mechanism to avoid multi-threaded synchronization problems, instance in class loading is instantiated.
(4) DCL double check mode
Public classSingleton {Private StaticSingleton Singleton;//static variable Private Singleton(){}//Private Constructors Public StaticSingletongetinstance() {if(Singleton = =NULL) {//First level checkSynchronized (Singleton.class) {if(Singleton = =NULL) {//second level checkSingleton =NewSingleton (); } } }returnSingleton } }
The highlight of this model is the getinstance () method, in which the Singleton is judged to be null two times, the first layer is judged to avoid unnecessary synchronization, and the second layer is judged to create the instance in the case of NULL. Specifically, let's analyze:
Assume that thread a executes to Singleton = new Singleton (); statement, which looks like a code, but it is not an atomic operation, this code will eventually be compiled into multiple assembly instructions, which will roughly do three things:
(a) Allocating memory to instances of Singleton
(b) Call the constructor of Singleton () to initialize the Member field;
(c) Point the Singleton object to the allocated memory space (that is, Singleton is not empty);
However, since the Java compiler allows the processor to execute in order, and before jdk1.5, the JMM (Java memory Model:java memory model) caches, registers, the write-back order to main memory, the above step b step c execution order is not guaranteed. That is, the order of execution may be a-b-c, or a-c-b, if it is the latter point of order, and precisely in the C execution, B is not yet executed, is switched to thread B, this time because the singleton is executed in the process a step c, is not empty, so, Thread B takes the singleton directly and then makes an error when it is used. This is the problem of the DCL failure.
But after JDK1.5, the official gave the volatile keyword, changing the code defined by singleton to:
privatevolatilestatic Singleton singleton; //使用volatile 关键字
This solves the problem of the DCL failure.
(5) Static internal class Singleton mode
public Class Singleton {private singleton () {}; Span class= "Hljs-comment" >//private constructor public Static final Singleton getinstance () {return
singletonholder.instance; } //defined static inner class private static class singletonholder {private static final Singleton INSTANCE = new Singleton (); //the place where the instance was created } }
When the Singleton class is loaded for the first time, the instance is not initialized, and only the getinstance () method of Singleton is called for the first time to cause instance to be initialized. Therefore, calling the getinstance () method for the first time causes the virtual machine to load the Singletonholder class, which not only ensures uniqueness of the Singleton object, but also delays the instantiation of the Singleton.
(6) enumeration of single cases
Several of the previous singleton patterns are implemented in a slightly cumbersome way, or in certain situations. The following describes the implementation of an enumeration singleton pattern:
publicenum Singleton { //enum枚举类 INSTANCE; publicvoidwhateverMethod() { } }
The biggest advantage of enumerating the singleton patterns is that it is simple to do, enumerations are the same in Java as normal classes, not only can have fields, but also have their own methods, the most important is that the default enumeration instance is thread-safe, and in any case, it is a single case. Even in the process of deserialization, the enumeration singleton does not regenerate the new instance. In several other ways, the following methods must be added:
privatereadResolve() throws ObjectStreamException{ return INSTANCE;}
To ensure that no new objects are generated when deserializing.
(7) Using a container to implement a singleton mode
In addition to the above several common ways of implementing a singleton, there is another class of implementation, the code is as follows:
Public classSingletonmanager {Private Staticmap<string, object> objmap =NewHashmap<string,object> ();//using HashMap as the cache container Private Singleton() { } Public Static void Registerservice(String key, ObjectInstance) {if(!objmap.containskey (key)) {Objmap.put (key, instance);//The first time is to deposit a map} } Public Static Objectgetservice(String key) {returnObjmap.Get(key);//Returns the object corresponding to the key}}
At the beginning of the program, a variety of singleton patterns are injected into a unified management class, and objects of the corresponding type are obtained according to key when used.
In the Android source code, when the app starts, the virtual machine will register various servicefetcher, such as the Layoutinflater Service, the first time it loads the class. These services are stored in a hashmap in the form of key-value pairs, where the user simply acquires the corresponding servicefetcher based on key, and then obtains the specific service object through the GetService function of the Servicefetcher object. When first fetched, the Servicefetcher's Creatservice function is called to create the service object, and then the object is cached in a list, fetched directly from the cache the next time it is fetched, avoiding repeated creation of the object, thus achieving the effect of the singleton. System core Services in Android exist in a single case, reducing resource consumption.
Summary: Regardless of the form of implementation of the Singleton mode, their core principle is to privatize the constructor, and through the static public method to obtain a unique instance, in this acquisition process must ensure the security of the thread, but also to prevent deserialization caused by the regeneration of the instance object.
Seven ways to approach the single-instance mode of Android design mode