Introduction to the

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.

  • Advantages: Only one instance in memory, reducing memory overhead, especially frequent instance creation and destruction (e.g., management school home page cache). Avoid multiple resources (such as write file operations).

  • Disadvantages: No interface, no inheritance, conflicts with the single responsibility principle, a class should only care about internal logic, not how to instantiate outside.

Pay attention to

  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.
  4. If a singleton is loaded by different class loaders, it is possible to have multiple instances of a singleton class.
  5. If Singleton implements the Java.io.Serializable interface, then instances of this class can be serialized and restored.

Several implementations of singleton pattern

1, lazy, thread is not safe

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
  • Multithreading security: No
  • Lazy Loading: it is
  • 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.

2, lazy, thread safety

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
  • Multithreaded security: Yes
  • Lazy Loading: it is
  • Description: This approach is very lazy, initializing only on the first call, avoids memory waste, and works well in multithreading. However, it is inefficient and requires no synchronization 99% of the time.

hungry

public class Singleton {

    private static final Singleton INSTANCE = new Singleton();

    private Singleton(a) {}public static Singleton getInstance(a) {
        returnINSTANCE; }}Copy the code
  • Multithreaded security: Yes
  • Lazy Loading: no
  • Description: This method is more common, but prone to generate garbage objects. Without locking, execution efficiency will be improved. Class is initialized at load time, wasting 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.

4, hungry, variant

public class Singleton {
    private static Singleton instance;

    static {
        instance = new Singleton();
    }

    private Singleton(a) {}public static Singleton getInstance(a) {
        returninstance; }}Copy the code
  • Multithreaded security: Yes
  • Lazy Loading: no
  • Description: Similar to the third method, the instance is instantiated during class initialization.

Register/static inner class

public class Singleton {

    private Singleton(a) {}public static Singleton getInstance(a) {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        private static final Singleton INSTANCE = newSingleton(); }}Copy the code
  • Multithreaded security: Yes
  • Lazy Loading: it is
  • Description: This method also uses the classloder mechanism to ensure that the instance is initialized with only one thread, which is different from the third and fourth methods (subtle differences) : The third and fourth ways are to instantiate the instance as soon as the Singleton class is loaded (without a lazy loading effect), while the Singleton class is loaded and the instance does not have to be initialized. Because the SingletonHolder class is not actively used, instance is instantiated only when the display shows loading the SingletonHolder class by calling the getInstance method. On the other hand, I don’t want to instantiate the Singleton class when it loads because I can’t be sure that the Singleton class might be used actively somewhere else to get loaded. This is obviously not the time to instantiate instance. At this point, this approach seems reasonable compared to the third and fourth approaches.

6, the enumeration

public enum Singleton {
    INSTANCE;

    public void whateverMethod(a) {}}Copy the code
  • Multithreaded security: Yes
  • Lazy Loading: no
  • Description: This approach, advocated by Effective Java author Josh Bloch, not only avoids multithreaded synchronization problems, 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.

7. Double-checked locking (DCL, double-checked locking)

public class Singleton {
    private volatile static Singleton instance;

    private Singleton(a) {}public static Singleton getInstance(a) {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = newSingleton(); }}}returninstance; }}Copy the code
  • Multithreaded security: Yes
  • Lazy Loading: it is
  • Description: This method uses double lock mechanism, safe and can maintain high performance in the case of multi-threading. The only drawback is writing.

conclusion

Of the above implementations, the first is not a singleton, the fourth and third are one, and the fifth can be written separately if it is. So there are usually five ways to write a singleton: slacker, villain, double check lock, enumeration, and static inner class. As for me, I prefer the third and fifth ways, which are easy to understand. The first and second methods are rarely used. If I have other special needs, I may use the seventh method.