Singleton mode of design pattern-including code examples and recommendations

tags: Design Patterns  

table of Contents

1. What is the singleton design pattern?

Two, the realization form of the singleton design pattern

1. Hungry Chinese style realization method 1 (recommended)

2. Hungry Chinese Realization Method Two

3. Lazy implementation method one (thread unsafe)

4. Lazy implementation method two (thread safety, but low efficiency)

5. Lazy man implementation mode three (thread unsafe)

6. Lazy man implementation four-DCL double-ended check + volatile (thread safety)

7. Static internal class method, JVM guarantee singleton (recommended)

8. Realize singleton mode through enumeration (not recommended)


1. What is the singleton design pattern?

Singleton mode is a commonly used software design mode. In its core structure, it only contains a special class called a singleton. byThe singleton pattern can ensure that there is only one instance of a class in the system that applies this pattern. That is, a class has only one object instance.

Class structure diagram

Implementation

  1. The constructor is privatized so that it cannot be instantiated by the new keyword outside the class.
  2. Generate a unique instantiated object within the class and encapsulate it as a private static type.
  3. Define a static method to return this unique object.

Two, the realization form of the singleton design pattern

Hungry Chinese, It is also easy to understand from the name, that is, "more frequent", the instance is already built when it is initialized, and whether you use it or not, you should build it first. The advantage is that there is no thread safety problem, and the disadvantage is a waste of memory space.

Lazy man, As the name implies, the instance is created when it is used. It is "lazy". It checks whether there is an instance when it is used, and returns if there is one, and creates a new one if there is none. There are two new ways of writing thread-safe and thread-unsafe. The difference is the Synchronized keyword.

1. Hungry man style realization method one (recommend

After the class is loaded into memory, a singleton is instantiated, and the JVM guarantees thread safety; simple to use;

But there are also disadvantages: whether it is used or not, the instantiation is completed when the class is loaded

/**
   * Hungry Chinese
   * After the class is loaded into memory, a singleton is instantiated, and the JVM guarantees thread safety
   * Simple and practical, recommended!
   * The only disadvantage: whether it is used or not, the instantiation is completed when the class is loaded
 * Class.forName("")
   * (If you don’t use it, what do you load it for)
 */
public class Singleton_01 {

    private static final Singleton_01 INSTANCE = new Singleton_01();

         // Private construction method
    private Singleton_01() {}

    public static Singleton_01 getInstance() {
        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        Singleton_01 singleton01 = Singleton_01.getInstance();
        Singleton_01 singleton02 = Singleton_01.getInstance();

        System.out.println(singleton01 == singleton02);
    }
}

2. Hungry Chinese Realization Method Two

Like the above Singleton_01, the singleton is instantiated through a static code block

/**
   * Same as 01
 */
public class Singleton_02 {

    private static final Singleton_02 INSTANCE;

         // Realize the instantiation of a singleton through a static code block
    static {
        INSTANCE = new Singleton_02();
    }

         // Private construction method
    private Singleton_02() {}

    public static Singleton_02 getInstance() {
        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        Singleton_02 singleton01 = Singleton_02.getInstance();
        Singleton_02 singleton02 = Singleton_02.getInstance();

        System.out.println(singleton01 == singleton02);
    }

}

3. Lazy man-style realization method one (Thread unsafe

The lazy style means that you need to use the instantiation of the class to create the object, but the following lazy style brings the problem of thread insecurity; it is very easy to get a different hashCode by using multiple threads to obtain the hashCode of a singleton object. The singleton objects are not the same, that is, there is a thread insecurity problem.

/**
 * lazy loading
   * Also known as lazy man
   * Although the purpose of on-demand initialization is achieved, it brings the problem of thread insecurity
 */
public class Singleton_03 {

    private static Singleton_03 INSTANCE;

         // Private construction method
    private Singleton_03() {}

    public static Singleton_03 getInstance() {
        if (INSTANCE == null) {
            try {
                TimeUnit.MILLISECONDS.sleep(1);
            } catch (Exception e){
                e.printStackTrace();
            }
            INSTANCE = new Singleton_03();
        }

        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(Singleton_03.getInstance().hashCode());
            }).start();

        }
    }
}

4. Lazy man type implementation mode two (Thread safe, but inefficient

After running [Lazy implementation method 1], you will find that there is a problem of multi-threading insecurity, because you can introduce Synchronized synchronization method to solve this problem, but it brings the problem of reduced efficiency.

Supplementary explanation: Synchronized here is a modified static synchronization method,In fact, it is to lock the Class object, commonly known as "class lock".

For the knowledge of the Sychronized keyword, please refer to:Java Concurrency-Synchronized Keyword and Lock Upgrade [Download Synchronized_Mind Map]

/**
 * lazy loading
   * Also known as lazy man
   * Although the purpose of on-demand initialization is achieved, it brings the problem of thread insecurity
   * The problem of thread safety can be solved by synchronized, but it also brings efficiency reduction
 */
public class Singleton_04 {
    private static Singleton_04 INSTANCE;

         // Private construction method
    private Singleton_04() {}

         // Lock the Singleton_04 object
    public static synchronized Singleton_04 getInstance() {
        if (INSTANCE == null) {
            try {
                TimeUnit.MILLISECONDS.sleep(1);
            } catch (Exception e){
                e.printStackTrace();
            }
            INSTANCE = new Singleton_04();
        }

        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(Singleton_04.getInstance().hashCode());
            }).start();

        }
    }
}

5. Lazy man realization method three (Thread unsafe

After running [Lazy Implementation Method Two], you will find that the introduction of Synchronized synchronization method to solve the multi-threaded insecurity problem, but it has brought the problem of reduced efficiency. For this reason, the granularity of Synchronized synchronization lock is reduced, and the efficiency is found to be improved, but the problem of multi-thread insecurity is still not solved

/**
 * lazy loading
   * Also known as lazy man
   * Although the purpose of on-demand initialization is achieved, it brings the problem of thread insecurity
   * It can be solved by synchronized, but it also reduces efficiency
   * By reducing the granularity of synchronized synchronization locks, it is found that the problem of multithreading insecurity still exists
 */
public class Singleton_05 {
    private static Singleton_05 INSTANCE;

         // Private construction method
    private Singleton_05() {}


    public static Singleton_05 getInstance() {
        if (INSTANCE == null) {
                         // In an attempt to improve efficiency by reducing synchronization code blocks, then it is impossible
            synchronized (Singleton_05.class) {
                try {
                    TimeUnit.MILLISECONDS.sleep(1);
                } catch (Exception e){
                    e.printStackTrace();
                }
                INSTANCE = new Singleton_05();
            }

        }

        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(Singleton_05.getInstance().hashCode());
            }).start();
        }
    }
}

6. Lazy man implementation method four-DCL double-ended check + volatile (Thread safe

It is possible to reduce the efficiency of synchronize, but there is still a problem of multi-threading insecurity; the introduction of DCL (Double Check Lock) + volatile (instruction reordering prohibited) solves the problem of multi-thread safety and improves efficiency.

DCL + Volatile, a combination of the advantages and disadvantages of both the lazy and hungry style. Looking at the code implementation below, the feature is that a layer of if conditional judgment is added inside and outside the Synchronized keyword, which not only ensures thread safety, but also improves execution efficiency compared to direct locking, and saves memory space. Using volatile here will more or less affect the performance, but considering the correctness of the program, it is worth sacrificing this performance. The advantage of DCL is high resource utilization. The singleton object is instantiated only when getInstance() is executed for the first time, which is highly efficient. The disadvantage is that the response is slightly slower the first time the load is loaded, and there are certain defects in the high concurrency environment, although the probability of occurrence is small. Although DCL solves the problems of resource consumption, redundant synchronization, thread safety, etc. to a certain extent, it still fails in some cases, that is, DCL fails.Java concurrent programming practice"Recommended for the bookStatic inner class singleton patternTo replace DCL.

/**
 * lazy loading
   * Also known as lazy man
   * Although the purpose of on-demand initialization is achieved, it brings the problem of thread insecurity
   * It can be solved by synchronized, but it also reduces efficiency
   * By reducing the granularity of synchronized synchronization locks, it is found that the problem of multithreading insecurity still exists
   * By adopting DCL, Double Check Lock, double-ended inspection mechanism, the probability of multi-threading insecurity is greatly reduced, but there are still multi-threading insecurity problems
 */
public class Singleton_06 {
    private static volatile Singleton_06 INSTANCE;

         // Private construction method
    private Singleton_06() {}


    public static Singleton_06 getInstance() {
        if (INSTANCE == null) {
                         // double check
            synchronized (Singleton_06.class) {
                if (INSTANCE == null) {
                    try {
                        TimeUnit.MILLISECONDS.sleep(1);
                    } catch (Exception e){
                        e.printStackTrace();
                    }
                    INSTANCE = new Singleton_06();
                }
            }

        }

        return INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(Singleton_06.getInstance().hashCode());
            }).start();
        }
    }
}

7. Static internal class method, JVM guarantee singleton (recommend

When loading external classes through JVM, internal classes will not be loaded, so that lazy loading can be achieved. One of the perfect writing methods is better than the first
When the Singleton class is loaded for the first time, INSTANCE is not initialized. Only when the getInstance method is called for the first time, the virtual machine loads Singleton_07_Holder and initializes INSTANCE, which not only ensures thread safety but also ensures the Singleton class Uniqueness, soIt is recommended to use the static inner class singleton pattern.

/**
   * Static inner class method
   * JVM guaranteed singleton
   * When loading external classes, internal classes will not be loaded, so lazy loading can be achieved
 *
   * One of the perfect writing methods, better than the first
 */
public class Singleton_07 {

         // Private construction method
    private Singleton_07() {}

    private static class Singleton_07_Holder {
        private final static Singleton_07 INSTANCE = new Singleton_07();
    }

         // not only lazy loading is realized, but also only once
         // If Singleton_07 is instantiated, Singleton_07_Holder will not be instantiated either, and will be loaded only when getInstance is called
    public static Singleton_07 getInstance() {
        return Singleton_07_Holder.INSTANCE;
    }

    public void m() {
        System.out.println("m");
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(Singleton_07.getInstance().hashCode());
            }).start();
        }
    }
}

8. Realize singleton mode through enumeration (Not recommended

The way of enumeration is a relatively rare implementation, but looking at the implementation of the above code, it is more concise and clear. Not only can solve thread synchronization, but also prevent deserialization.

The creation of the default enumeration instance is thread-safe, and it is a singleton in any case. The several singleton modes mentioned above are implemented. In one case, they will re-create the object, that is, deserialization, and a The singleton instance object is written to disk and then read back to obtain an instance. The deserialization operation provides the readResolve method, which allows developers to control the deserialization of the object. In the above several method examples, if you want to prevent the singleton object from being deserialized, it is to regenerate the object.

The advantage of enumeration singleton is its simplicity, but most application development rarely uses enumeration, and its readability is not very high.

/**
 * Not only can solve thread synchronization, but also prevent deserialization
 */
public enum Singleton_08 {

    INSTANCE;

    public void m() {}

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(Singleton_08.INSTANCE.hashCode());
            }).start();
        }
    }
}

to sum up:

The above 8 ways of writing, as for the actual projectWhich form of singleton mode you choose depends on your project itself, whether you have a complicated concurrent environment, or you need to control the resource consumption of singleton objects.

 


At the end of the article, I recommend some popular technical blog links to everyone

  1. Flinak related technical blog links
  2. Hadoop related technical blog links
  3. Spark core technology link
  4. JAVA related deep technical blog link
  5. Super dry goods-Flink mind map, it took about 3 weeks to write and proofread
  6. Deepen the core principles of JAVA JVM to solve various online faults [with case]
  7. Please talk about your understanding of volatile? --A recent "hardcore contest" between Xiao Lizi and the interviewer
  8. Talk about RPC communication, an interview question that is often asked. Source code + notes, package understanding
  9. In-depth talk about Java garbage collection mechanism [with schematic diagram and tuning method]

Welcome to scan the QR code below or search the official account "10 points for further study", we will push more and timely information to you, welcome to communicate!

                                           

       

 

 

Intelligent Recommendation

Design pattern - singleton mode

The Singleton Pattern involves a single class that is responsible for creating your own objects while ensuring that only a single object is created. This class provides a way to access its unique obje...

Design Pattern: Singleton mode

The English meaning of Singleton is single, that is, only one person, applied to the object-oriented language, usually translated as a singleton: a single instance (Instance). Many times, you will nee...

[Design Pattern] singleton mode

What is the singleton mode? In Single Pattern, only one instance of an object can be represented by a singleton. The singleton pattern is implemented in such a way that a class can only return a refer...

Design Pattern -- Singleton mode

The singleton mode is one of the most commonly used modes in design mode. It is generally applied to positioning management, thread management, file management, network management, etc., allowing a si...

More Recommendation

Singleton mode of design pattern

1. Definition        Singleton Pattern: The singleton pattern ensures that a certain class has only one instance, and it instantiates itself and provides this instance to...

2017.11.2 LeetCode - 70. Climbing Stairs - 100. Same Tree - 717. 1-bit and 2-bit Characters

717. 1-bit and 2-bit Characters We have two special characters. The first character can be represented by one bit 0. The second character can be represented by two bits (10 or 11). Now given a string ...

Branch control structure in Java

20. Sequence structure The most basic structure of Java is the sequential structure, unless otherwise specified, it is executed in order, sentence by sentence Sequence structure is the simplest algori...

C ++ unary operator overloading

Reproduced in: https: //blog.51cto.com/frankniefaquan/1934028...

JDK source code parsing - StringBuffer

First take a look at the definition of StringBuffer Defined as a final form, mainly for the sake of "efficiency" and "security". Its parent class AbstractStringBuilder is defined a...

Copyright  DMCA © 2018-2026 - All Rights Reserved - www.programmersought.com  User Notice

Top