Singleton mode of Android design pattern-the most widely used mode

1. What is the singleton pattern?

The singleton mode is to ensure that there is only one instance of a certain class, and to instantiate and provide this instance to the entire system. When applying the singleton pattern, the class of the singleton object must ensure that only one instance exists. In many cases, the entire system only needs to have one global object, which helps us coordinate the overall behavior of the system.

Second, the use scenario of singleton mode

When objects cannot be constructed freely, ensure that a certain class has one and only one object to avoid multiple objects that consume too much resources, or there should only be one and only one object of a certain type. For example, creating an object consumes too many resources. If you want to access resources such as IO and databases, you must consider using the singleton mode.

Three, the key points to realize the singleton mode

1. The constructor is not open to the outside world, generally Private;
by privatizing the constructor of the singleton class, the client code cannot manually construct the object of the singleton class in the form of new.
2. Return the singleton class object through a static method or enumeration; the
singleton class will expose a public static method, and the client needs to call this static method to obtain the only object of the singleton class.
3. Make sure that there is one and only one singleton object, especially in a multithreaded environment;
you need to ensure thread safety in the process of obtaining this singleton object , that is, there are only and only objects to construct a singleton in a multithreaded environment One. (More difficult to implement)
4. Make sure that the singleton object will not rebuild the object during deserialization.

Four, several implementation methods of singleton mode

1. Hungry man mode

public class Singleton{
    private static final Singleton mInstance = new Singleton();
    // 构造函数私有
    private Singleton(){
    }
    // 公有的静态函数,对外暴露获取单例对象的接口
    public static Singleton getInstance(){
        return mInstance;
    }
}

The hungry man mode initializes a static object when it is declared.

  1. Disadvantages : The object will be recreated during deserialization.

2. Slacker mode

public class Singleton{
    private static Singleton mInstance;
    private Singlrton(){
    }
    public static synchronized Singleton getInstance(){
        if(mInstance == null){
            mInstance = new Singleton();
        }
        return mInstance;
    }
}

The lazy man mode is to declare a static object and initialize it when the user calls getInstance for the first time.

  1. Advantages : Singletons will only be instantiated when they are used, which saves resources to a certain extent;
  2. Disadvantages : it needs to be instantiated in time when loading for the first time, the response is slow; the object will be recreated during deserialization;
  3. The biggest problem : the synchronized keyword is added to the getInstance() method, so every time getInstance() is called, synchronization is performed, which causes unnecessary synchronization overhead;
  4. Conclusion : Lazy man mode is generally not recommended .

3. Double CheckLock (DCL) to achieve singleton (recommended)

public class Singleton(){
    private volatile static Singleton mInstance = null;
    private Singleton(){
    }
    public void doSomething(){
        System.out.println("Do sth.");
    }
    public static Singleton getInstance(){
        if(mInstance == null){
            synchronized(Singleton.class){
                if(mInstance == null){
                    mInstance = new SIngleton();
                }
            }
        }
        return mInstance;
    }
}

Among them, adding the volatile keyword can solve the problem of DCL failure, but it will more or less affect the performance, but considering the correctness of the program, it is worth sacrificing this performance.

  1. Advantages : The singleton can be initialized only when needed, and the uniqueness of the singleton object can be guaranteed in most scenarios, and thread safety can be guaranteed. After the singleton object is initialized, getInstance is called without synchronization lock. The resource utilization rate is high, and the singleton object will be instantiated when getInstance is executed for the first time, which is highly efficient;
  2. Disadvantages : The response is slightly slower the first time it loads, and it occasionally fails due to the Java memory model. There are also certain defects in a high-concurrency environment, although the probability of occurrence is small; the object will be recreated during deserialization;
  3. Conclusion : In addition to the complicated concurrency scenario or the case of a version lower than JDK 6, the DCL mode is the most used singleton implementation.

4. Static inner class singleton mode (recommended)

public class Singleton(){
    
    
    private Singleton(){
    }
    public static Singleton getInstance(){
        return SingletonHolder.mInstance;
    }
    /**
     * 静态内部类
     */
     private static class SingletonHolder(){
    
    
         private static final Singleton mInstance = new Singleton();
     }
}

Although DCL to some extent, solve the resource consumption, redundant synchronization, thread-safety and other issues, but in some cases there will be double-checked locking (DCL) failure problem, it is recommended to use a static inner classes singleton pattern instead.

  1. Advantages : to ensure thread safety, to ensure the uniqueness of singleton objects, and to delay the instantiation of singletons;
  2. Disadvantages : the object will be recreated during deserialization ;
  3. Conclusion : This method is recommended to implement singleton mode.

5. Enumeration singleton

public enum SingletonEnum{
    INSTANCE;
    public void doSomething(){
        System.out.println("Do sth.");
    }
}
  1. Advantages: simple writing; the creation of default enumeration instances is thread-safe; it is a singleton under any circumstances, even when deserializing ;

6. Use containers to implement singleton mode

public class SingletonManager{ 
    private static Map<String,Object> objMap = new HashMap<String,Object>();
    private Singleton(){
    }
    public static void registerService(String key,Object mInstance){ 
        if(!objMap.containKey(key)){ 
            objMap.put(key,mInstance);
        }
    }
    public static ObjectgetService(String key){ 
        return objMap.get(key);
    }
}
  1. Advantages : reduce the user's use cost, hide the specific implementation from the user, and reduce the degree of coupling.

Five, summary

  1. The core principle : privatize the constructor, and obtain a unique instance through a static method. During the acquisition process, thread safety must be ensured to prevent deserialization from regenerating instance objects.

  2. Advantages :
    (1) Since the singleton mode has only one instance in the memory, memory expenditure is reduced, especially when an object needs to be created and destroyed frequently, and the performance cannot be optimized during creation or destruction. The advantage of the singleton mode is Obviously;
    (2) Since the singleton mode only generates one instance, the performance overhead of the system is reduced. When the generation of an object requires more resources, such as reading the configuration and producing other dependent objects, you can pass A singleton object is directly generated when the application is started, and then permanently resides in the memory to solve it;
    (3) The singleton mode can avoid multiple occupation of resources, such as a file writing operation, because only one instance exists in the memory. Avoid writing to the same resource file at the same time;
    (4) The singleton mode can set a global access point in the system to optimize and share resource access. For example, a singleton class can be designed to be responsible for the mapping processing of all data tables.

  3. Disadvantages :
    (1) The singleton mode generally has no interface, and it is difficult to extend, except to modify the code;
    (2) If the singleton object holds Context, it is easy to cause memory leaks, and you need to pay attention to the information passed to the singleton object. Context is preferably Application Context.

  4. Extension :
    Q: How to prevent singleton objects from being regenerated when they are deserialized in the above examples?
    A: Through serialization, a singleton instance object can be written to disk and then read back to effectively obtain an instance. Even if the constructor is private, it is already possible to create a new instance of the class in a special way during deserialization, which is equivalent to calling the constructor of the class. The deserialization operation provides a very special hook function. The class has a private, instantiated method readResolve() , which allows developers to control the deserialization of the object.
    The following methods can be added to the above examples to prevent singleton objects from being regenerated when they are deserialized :

private Object readResolve() throws ObjectStreamException{
    return mInstance;
}

That is, the mInstance object is returned in the readResolve() method, instead of regenerating a new object by default.

Guess you like

Origin blog.csdn.net/CHITTY1993/article/details/52234747