What is the singleton pattern?

Definition: ensure that a class has only one instance, and instantiate and provide this instance scenario to the entire system, that is: ensure that a class has only one object scenario, avoid creating multiple objects consume too many resources, or there should be only one object of a certain type.

Key to building a singleton pattern:

1. Constructors are not open to the public and are generally Private

2. Return a singleton class object via a static method or enumeration

3. Ensure that there is only one object for a singleton class, especially in a multithreaded environment

4. Ensure that singleton class objects are not rebuilt when deserialized

Singleton pattern construction method:

1. Hungry

2. Double Check

3. The singleton pattern for static inner classes

4. The container implements the singleton pattern

5. Serialization deserialization singleton pattern (readResolve)

6. Enumerate singleton patterns

 

Code examples:

1. Hungry

public class Singleton {
	private Singleton(a){}private static final Singleton Instance=new Singleton();
	public static Singleton getInstance(a){ 
		returnInstance; }}Copy the code

2. Double Check

public class Singleton {
	private Singleton(a){}private static volatile Singleton Instance=null;
	public static Singleton getInstance(a){ 
		if(Instance==null) {synchronized (Singleton.class) {
				if(Instance==null)
				{
					Instance=new Singleton();
					returnInstance; }}}returnInstance; }}Copy the code

The semantics of volatile is “forbid CPU to reorder the bytecode instructions”. Since the computer is multi-core, the JVM will reorder the bytecode instructions to better execute it, so it may occur that the bytecode instruction of thread A is halfway executed. The bytecode instruction of thread B will execute the franchising and first modify the franchising, resulting in that, when the bytecode of thread A executes the franchising to new, the franchising has already been initialized. This is where the problem arises, so you need to disable bytecode reordering.

3. Static inner class singleton pattern

public class Singleton {
	private Singleton(a){}
	private static Singleton getInstance(a){
		return SingletonHolder.Instance;
	}
	/** * static inner class */
	private static class SingletonHolder{
		private static final Singleton Instance = newSingleton(); }}Copy the code

Instance is not initialized when the Singleton class is first loaded. Instance is initialized only when the Singleton’s getInstance method is called for the first time. The first call to the getInstance method causes the virtual machine to load the SingletonHolder class, which is recommended because it ensures thread-safety and uniqueness of singleton objects, but also delays singleton instantiation.

4. Implement the singleton pattern using containers

public class SingletonManager {
    private static Map<String, Object> objMap = new HashMap<String, Object>();
    private SingletonManager(a){}// Inject multiple singleton types into a unified management class, which gets objects of the corresponding type based on the key when used
    public static void registerService(String key, Object instance)
    {
        if(!objMap.containsKey(key)){
            objMap.put(key, instance);
        }
    }
    public static Object getService(String key){
        returnobjMap.get(key); }}Copy the code
 
Copy the code

5. Implement the singleton pattern using serialization

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
 
public class SerSingleton implements Serializable {
 
    private static final long serialVersionUID = 1L;
    String name;
 
    private SerSingleton(a) {
        System.out.println("Singleton is create");
        name = "SerSingleton";
    }
 
    private static SerSingleton instance = new SerSingleton();
 
    public static SerSingleton getInstance(a) {
        return instance;
    }
 
    public static void createString(a) {
        System.out.println("createString in Singleton");
    }

    private Object readResolve(a){
        return instance;
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        SerSingleton s1 = null;
        SerSingleton s = SerSingleton.getInstance();
 
        FileOutputStream fos = null;
        ObjectOutputStream oos = null;
 
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        try {
            fos = new FileOutputStream("SerSingleton.obj");
            oos = new ObjectOutputStream(fos);
            oos.writeObject(s);
        } finally {
            oos.flush();
            oos.close();
            fos.close();
        }
 
        try{
            fis = new FileInputStream("SerSingleton.obj");
            ois = new ObjectInputStream(fis);
            s1 = (SerSingleton) ois.readObject();
        }finally{ ois.close(); fis.close(); } System.out.println(s == s1); }}Copy the code

The serialization singleton pattern requires the readResolve method to be implemented.

6. Use enum to implement the singleton mode

public enum SingletonClass implements Serializable {
 
    INSTANCE;
    private static final long serialVersionUID = 1L;
 
    private String name;
 
    public void test(a) {
        System.out.println("The Test!");
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getName(a) {
        return name;
    }
 
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        SingletonClass s1 = null;
        SingletonClass s = SingletonClass.INSTANCE;
 
        FileOutputStream fos = null;
        ObjectOutputStream oos = null;
 
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        try {
            fos = new FileOutputStream("SingletonClass.obj");
            oos = new ObjectOutputStream(fos);
            oos.writeObject(s);
        } finally {
            oos.flush();
            oos.close();
            fos.close();
        }    
        try {
            fis = new FileInputStream("SingletonClass.obj");
            ois = new ObjectInputStream(fis);
            s1 = (SingletonClass) ois.readObject();
        } finally{ ois.close(); fis.close(); } System.out.println(s == s1); }}Copy the code

The implementation of the container singleton pattern, in Android, we use the Context getSystemService(key) method, is the use of the container singleton pattern. Eg: WIndowsManagerService, ActivityManagerService, etc. When the vm loads the class for the first time, various services are registered. These services are stored in a HashMap as key-value pairs. Users only need to obtain specific Service objects based on keys.