Art is long, life is long

An overview,

The Singleton Pattern is one of the simplest design patterns in Java. This type of design pattern is the creation pattern, which provides the best way to create objects.

This pattern involves a single class that is responsible for creating its own objects while ensuring that only a single object is created. This class provides a way to access its unique objects directly, without instantiating the objects of the class.

Note:

  • 1. A singleton class can have only one instance.
  • 2. A singleton class must create its own unique instance.
  • 3. The singleton class must provide this instance to all other objects.

Two, seven kinds of realization

2.1 slacker – Threads are not safe

Whether to initialize Lazy: Yes

Whether multithreading is safe: No

Implementation difficulty: easy

Description: This is the most basic implementation, the biggest problem with this implementation is that it does not support multi-threading. Synchronized is not strictly a singleton mode because it is not locked. This approach to lazy loading is obviously not thread-safe and does not work well in multiple threads.

public class Singleton {  
    private static Singleton instance;  
    private Singleton (a){}  
  
    public static Singleton getInstance(a) {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    	returninstance; }}Copy the code

2.2 slacker — thread-safe

Whether to initialize Lazy: Yes

Whether multithreading is safe: Yes

Implementation difficulty: easy

Description: This approach is very lazy and can work well in multiple threads, but it is inefficient and does not require synchronization 99% of the time. Advantages: Initialization is performed only on the first call, avoiding memory waste. Disadvantages: synchronized must be added to ensure singletons, but locking will affect efficiency. The performance of getInstance() is not critical to the application (this method is used infrequently).

public class Singleton {  
    private static Singleton instance;  
    private Singleton (a){}  
    public static synchronized Singleton getInstance(a) {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    	returninstance; }}Copy the code

2.3 hungry

Lazy initialization: No

Whether multithreading is safe: Yes

Implementation difficulty: easy

Description: This method is more common, but prone to generate garbage objects. Advantages: Without locking, the execution efficiency will be improved. Disadvantages: Class initialization on load, waste of memory. It avoids multithreading synchronization problems based on the ClassLoader mechanism. However, instance is instantiated when the class is loaded. Although there are many reasons for class loading, in singleton mode the getInstance method is mostly called, However, there is no other way (or static way) to load the class, so initializing instance is obviously not lazy.

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (a){}  
    public static Singleton getInstance(a) {  
    	returninstance; }}Copy the code

2.4. Hangry style — variant

As before, we just moved the creation of singletons to static blocks.

public class Singleton {  
    private static Singleton instance;
    
    static {
        instance = new Singleton();
    }
    
    private Singleton (a){}  
    public static Singleton getInstance(a) {  
    	returninstance; }}Copy the code

2.5. Enumeration

JDK version: JDK1.5

Lazy initialization: No

Whether multithreading is safe: Yes

Implementation difficulty: easy

Description: This implementation is not yet widely adopted, but it is the best way to implement the singleton pattern. It is more concise, automatically supports serialization mechanisms, and absolutely prevents multiple instantiations. This approach, advocated by Effective Java author Josh Bloch, not only avoids multithreaded synchronization issues, but also automatically supports serialization, prevents deserialization from recreating new objects, and absolutely prevents multiple instantiations. However, since the enum feature was added later in JDK1.5, writing this way is somewhat unfamiliar and rarely used in practice. Private constructors cannot be called through Reflection Attack.

public enum Singleton {  
    INSTANCE;  
}
Copy the code

2.6 double check lock type

JDK version: JDK1.5

Whether to initialize Lazy: Yes

Whether multithreading is safe: Yes

Implementation difficulty: Complex

Description: This method uses double lock mechanism, safe and can maintain high performance in the case of multi-threading. The performance of getInstance() is critical to the application.

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (a){}  
    public static Singleton getSingleton(a) {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = newSingleton(); }}}returnsingleton; }}Copy the code

Note:

  1. The use of volatile to prevent exposure of an incomplete singleton instance that has not been initialized;
  2. Double null check, the first judgment can avoid frequent locking, the second judgment can block the redundant thread to create the instance;
  3. Lock to ensure thread safety (only one instance)

This approach is often used in interview questions and is often handwritten.

2.7. Static inner Classes

Whether to initialize Lazy: Yes

Whether multithreading is safe: Yes

Implementation difficulty: Average

Description: This method can achieve the same effect of double lock mode, but the implementation is simpler. Lazy initialization for static fields should be used instead of double-checking. This approach is only suitable for static domains, and double-check can be used when the instance domain requires delayed initialization.

public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (a){}  
    public static final Singleton getInstance(a) {  
    returnSingletonHolder.INSTANCE; }}Copy the code

Third, summary

Of the 7 design patterns listed above, thread 1 is not safe and can be excluded, while thread 3 and 4 are actually one, which can be reduced to 5: lazy, hungry, static inner class, enumeration, and double check lock.