The singleton pattern

  • Belongs to the creation mode

  • Do the instantiation yourself, privatize the constructor

The target of the singleton pattern

  • Instance uniqueness
  • Thread safety

In any case, you need to ensure that there is only one instance of a class, that multiple instances are not created because of multithreaded access, and that new efficiency issues are not introduced because of multithreading

1 the hungry

// Principle: Static objects are initialized by the JVM when the class is loaded. This process is thread safe (class initialization locks ensure thread safety). Lazy loading cannot be implemented
//1.1 Static constants
public class Singleton {
    // Based on the Class Loader mechanism
	private final static Singleton INSTANCE = new Singleton();
	// Private constructor to prevent external direct instantiation
	private Singleton(a){}
	public static Singleton getInstance(a){
    	returnINSTANCE; }}//1.2 Static global variables
public class Singleton {
    private static Singleton sInstance = new Singleton();
    private Singleton(a) {}
    public static Singleton getInstance(a) {
        returnsInstance; }}//1.3 Static global variables static code block
public class Singleton {
	private static Singleton sInstance;
	static {
   	 	sInstance = new Singleton();
	}
	private Singleton(a) {}
	public Singleton getInstance(a) {
    	returnsInstance; }}Copy the code
  • The synchronization problem of multiple threads is avoided through workarounds
  • Extended class loading time, low efficiency
  • If it is loaded, it is a waste of resources if it is not used

2 LanHanShi

//2.1 Thread is not safe
public class Singleton {
    private static Singleton sInstance;
    private Singleton(a) {}
    If (singleton == null) {if (singleton == null) {if (singleton == null) {if (singleton == null) {if (singleton == null) {if (singleton == null)}
    public static Singleton getInstance(a) {
        if (sInstance == null) {
            sInstance = new Singleton();
        }
        returnsInstance; }}GetInstance () = synchronized
public class Singleton {
    private static Singleton sInstance;
    private Singleton(a) {}
    // The thread synchronizes getInstance(), which adds a lot of overhead
    public synchronized static Singleton getInstance(a) {
        if (sInstance == null) {
            sInstance = new Singleton();
        }
        returnsInstance; }}Synchronized (Singleton. Class) {} is not thread safe
public class Singleton {
	private static Singleton sInstance;
	private Singleton(a) {}
	public static Singleton getInstance(a) {
    if (sInstance == null) {
        // Multiple threads will still be able to tell by if that the instantiated code is synchronized but will be instantiated multiple times
        synchronized (Singleton.class) {
            sInstance = newSingleton(); }}returnsInstance; }}Synchronized (singleton.class) {} {// synchronized(singleton.class) {}
public class Singleton {
    private static Singleton sInstance;
    private Singleton(a) {}public static Singleton getInstance(a) {
        synchronized (Singleton.class) {
            if (sInstance == null) {
                sInstance = newSingleton(); }}returnsInstance; }}Copy the code

3 Double check the lock

// Double-checked Locking DCL
public class Singleton {
    // The volatile keyword declaration disables instruction reordering by adding a lock at compile time
    private static volatile Singleton sInstance;
    private Singleton(a) {}
    public static Singleton getInstance(a) {
        // Decide once to avoid unnecessary synchronization locks
        if (sInstance == null) {
            synchronized (Singleton.class) {
                if (sInstance == null) {
                    sInstance = newSingleton(); }}}returnsInstance; }}Copy the code
  • Thread safety, delay loading, high efficiency

  • Why volatile is necessary

    The system executes sInstance = new Singleton(), which is not completed at one time. It is roughly divided into three steps

    1 allocate memory for the Singleton instance to be created. 2 Call the corresponding Singleton constructor. 3 Point sInstance to the previously allocated memory space

    Instruction reordering can occur with 3 followed by 2, so when one thread executes 1 and 3 but does not execute 2 (an instance will be created later), another thread can create another instance through null judgment

Static inner class

//
public class Singleton {
    private Singleton(a) {}
	// Static inner class
    private static class SingletonInstanceHolder {
        Class static properties are initialized only the first time the class is loaded
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance(a) {
        returnSingletonInstanceHolder.INSTANCE; }}Copy the code
  • Avoid thread insecurity, delay loading, high efficiency

5 the enumeration type

public enum Singleton {
    INSTANCE;
    public void doSome1(a){}}Copy the code
  • Thread insecurity is avoided
  • Prevents deserialization from recreating new objects

Pay attention to

1 The above scheme does not consider deserialization

  • The readResolve() method is called to regenerate an instance during deserialization, so overrides are required to return a singleton directly

2 The singleton concept can also be realized by using Map to store values

Android has its own Singleton abstract class


/**
 * Singleton helper class for lazily initialization.
 *
 * Modeled after frameworks/base/include/utils/Singleton.h
 *
 * @hide* /
/ / source location/frameworks/base/core/Java/android/util/Singleton. Java
public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create(a);

    public final T get(a) {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            returnmInstance; }}}Copy the code

Consider: It’s cheap to construct a normal object in Java, so why bother with singletons if they’re lazy?

  • Load time: Usually the singleton life cycle is long. Assuming that the singleton class itself involves a lot of business logic during initialization, which is complicated or time-consuming, is not suitable for lazy loading, but needs to be loaded in advance?
  • After loading: Suppose the singleton class is initialized to hold a large amount of resources. If it is not used after initialization, it will be wasteful. Then there is always the risk that memory will not be used or not.

So if you make the singleton class light, don’t you have to worry too much about lazy loading?