This is the 6th day of my participation in the August More Text Challenge

This paper mainly analyzes the changes of singleton pattern in the evolution process, and summarizes the common singleton form in singleton pattern writing method, hoping to help you better manage the iteration process of the singleton pattern.

Generally speaking, there are mainly two forms of slacker and hungry in the construction of singleton pattern, and the general evolution process is basically as follows:

Since hanhanian singletons are relatively simple, we will not discuss them here, but focus on analyzing the writing methods of the latter ones

Advantages of singleton pattern:

1. Saves memory and resources

2. Ensure the correctness of the results and avoid errors caused by resource competition

For example, when writing to a file, it is easy to cause inconsistencies if multiple instances simultaneously read and write to the file content.

Lazy singleton analysis

Lazy singletons are instances that are built when the instance is used, so that the constructed object is guaranteed to be used. Avoid the problem of building it and not using it.

The basic version of lazy singletons

    // lazy singleton
    public class LazySingleton {
        private static LazySingleton lazySingleton = null;

        public static LazySingleton getInstance(a){
            if (lazySingleton == null) {return new LazySingleton();
            }
            returnlazySingleton; }}Copy the code

There is a thread-safe problem with writing this way, so let’s start analyzing and solving this problem

In general, writing lazy singletons without the restriction of synchronized blocks can lead to threading problems, but the restriction of synchronized keyword can also cause problems if the problem is incorrectly added.

Synchronized still has problems using the same methods as shown below color{red} Synchronized still has problems using the same methods as shown below

public static  LazySingleton getInstance(a){
    if (lazySingleton == null) {synchronized (LazySingleton.class) {
          return newLazySingleton(); }}return lazySingleton;
}
Copy the code

Although the synchronized keyword is added at this time, but also faced with the thread is not safe. Suppose there are two threads A and B running synchorinzed (Lazysingleton.class) at the same time.

Because of lock, can only have one thread into execution, as if A thread enters, construct the object, the program exits the lock is released, B will get the lock information at this time, but at the moment, B will execute A build logic after get the resources, construct an object information, at this time back to construct two different lazySingleton object, This is not a singleton per se.

There’s a new twist to this insecure lazy singleton: double-checked locking.

Double check the lock list for example

// Double check the lock mechanism singleton mode
public class LazySingleton {
   private volatile static LazySingleton lazySingleton = null;

   public static  LazySingleton getInstance(a){
       if (lazySingleton == null) {
           synchronized (LazySingleton.class) {
               if (lazySingleton == null) {
                   lazySingleton = newLazySingleton(); }}}returnlazySingleton; }}Copy the code

In fact, it is possible to remove the first weight, but this is equivalent to changing the method to single-threaded mode, resulting in increased performance loss. In this case, it is equivalent to locking the class, which ensures that only one thread can enter the locked object for execution at a time, causing performance problems. Therefore, it is not recommended to delete the class.

Extension: Standard double-checked locks are typically modified with the volatile keyword because:

Avoid the problem of reordering in Java because Java code is automatically optimized in the JVM, and the operation of new creating an object is not an atomic operation, which involves reordering instructions.

Generally speaking, instantiation mainly goes through the following steps:

1. Allocate instance space \color{#00BFFF} 1 Allocate instance space 1. Allocate instance space

Initialize the singleton object message \color{#00BFFF} 2. Initialize the Singleton object. 2. Initialize the Singleton object

3. The instace object is not null\color{#00BFFF} 3. If the initialized object information points to the allocated memory space, the Instace object is not null3. The instace object is not null when the initialized object information points to the allocated memory space

When the instruction is reordered, the third step is better than the second step. In this case, an empty object may be obtained. Therefore, the KEYWORD volatiled can be used to prevent THE INSTRUCTION reordering of THE JVM. Therefore, the volatile keyword is usually used for double-checked locking.

If you add Synchorinzed to the method that gets the singleton, it is completely thread-safe because only one thread can enter the method at a time, as shown in the figure below. There are no threading problems with this singleton pattern. The specific writing is as follows:

public static synchronized  LazySingleton getInstance(a){
   if (lazySingleton == null) {return new LazySingleton();
   }
   return lazySingleton;
}
Copy the code

Static inner class singleton

This form takes the form of hungry, but differs from hungry, which is instantiated as soon as the class is loaded, without lazy-loading. In the form of static inner class, the class is loaded only when the method expression is called, so as to complete the creation of the loaded singleton.

The specific writing is as follows

// a singleton in the form of static inner classes
public class StaticInnerClassSingleton {
    private static class InnerClass {
        private static StaticInnerClassSingleton
                staticInnerClassSingleton = new StaticInnerClassSingleton();
    }

    public StaticInnerClassSingleton getInstance(a) {
        returnInnerClass.staticInnerClassSingleton; }}Copy the code

Enumerated the singleton

Effective says that the best singleton implementation pattern is the enumeration pattern. Let the JVM help us with thread safety and single instance issues by taking advantage of enumerations.

The writing rules of enumerated singletons are as follows

summary

Singleton pattern can be said to be one of the most commonly used design patterns. At the same time, its iterative evolution path is also worth further thinking. From an ordinary singleton, it can be extended to synchronized, for example:

  • The effect of the synchroized keyword

  • Synchroized Usage mode

  • The principle behind synchroized

  • Synchroized Upgrade process and upgrade details for intermediate, lightweight, and weight locks

  • What are the disadvantages of synchroized and the difference from Lock

    With a simple singleton, it is easy to extend to the problem of concurrency. When you mention the keyword VOLATIled, is the underlying principle, advantage and implementation principle obvious?

Simple things often contain not simple things, knowledge is endless, I hope you and I can always keep an apprentice heart. Come on ~ ~