The singleton mode of the 30-day re-learning design mode

Singleton mode

The singleton pattern may be one of the simplest design patterns in design patterns, and it may also be one of the most commonly used design patterns.

The singleton pattern ensures that there is only one instance of a class, and the idea is to privatize the constructor. When we want to control the number of instances, we can consider using the singleton pattern.

In daily life, when we work, a person has a direct superior, and the connection pool of the database will not be created repeatedly. These are examples of singletons.

There are many ways to implement the singleton mode, mainly in the implementation of whether it supports the lazy man mode, and whether it uses various techniques in thread safety. Of course, there are some scenarios that do not need to consider lazy loading, that is, the lazy mode, and will directly use static static classes or attributes and methods for processing for external calls.

The realization of seven singleton patterns

1. Slacker mode (thread is not safe)

The implementation is very simple, just create an instance when there is no instance. The instance is created only when it is used for the first time. Because there is no lock, it is thread-unsafe, so multi-threaded mode is not supported.

public class LazyMan(){
    
    
     private LazyMan(){
    
    
        //私有化构造方法
    }
    
    private static LazyMan lazyMan;
    
    public static LazyMan getInstance(){
    
    
        if(lazyMan == null){
    
    
            lazy = new LazyMan();
        }
        return lazyMan;
    } 
}

2. Lazy man mode (thread safety)

After locking, thread safety is achieved, but it will reduce efficiency

public class LazyMan(){
    
    
     private LazyMan(){
    
    
        //私有化构造方法
    }
    
    private static LazyMan lazyMan;
    
    public static synchronized LazyMan getInstance(){
    
    
        if(lazyMan == null){
    
    
            lazy = new LazyMan();
        }
        return lazyMan;
    } 
  }
}

3. Hungry man mode

As the name suggests, they are hungry and thirsty, and the level of hunger and thirst is the same as mine. Because there is no lock, the execution efficiency will be very high, but it may cause a waste of memory.

public class Hungry(){
    
    
    private Hungry(){
    
    
        
    }
    
    private final static Hungry hungry = new Hungry();
    public static Hungry getInstance(){
    
    
        return hungry;
    } 
}

4. Inner class (thread safety)

The singleton mode implemented by using the static inner class of the class not only ensures thread safety but also lazy loading, and at the same time does not consume performance due to the locking method. This is mainly because the JVM virtual machine can guarantee the correctness of multi-threaded concurrent access, that is, the construction method of a class can be loaded correctly in a multi-threaded environment.

public class Holder(){
    
    
    private Holder(){
    
    
        
    }
    
    public static class InnerClass(){
    
    
        private final static Holder holder = new Holder();
    }
    
    public static Holder getInstance(){
    
    
        return InnerClass.holder;
    } 
}

5. Double detection lock mode (DCL)

The double-locking method is an optimization of method-level locks, which reduces the time-consuming part of obtaining instances and also satisfies the lazy loading mode.

public class LazyMan(){
    
    
     private LazyMan(){
    
    
        
    }
    private volatile static LazyMan lazyMan;//必须加上volatile保证
    
    public static LazyMan getInstance(){
    
    
        if(lazyMan == null){
    
    
            synchronized(LazyMan.class){
    
    
                if(lazyMan==null){
    
    
                    lazyMan = new LazyMan();//不是原子性操作
                }
            }
        }
        return lazyMan;
   }

6. CAS "AtomicReference" (thread safety)

Through the atomic class AtomicReference provided by the Java Concurrency Library, AtomicReference can encapsulate a generic instance to support concurrent access.

The advantage of using CAS is that there is no need to use traditional locking methods to ensure thread safety, but rely on the busy algorithm of CAS and the implementation of the underlying hardware to ensure thread safety. Compared with other lock implementations, there is no thread switching and blocking, there is no additional overhead, and greater concurrency can be supported. But it will generate busy waiting, if not, it will keep infinite loop.

public class Singleton(){
    
    
    private Singleton(){
    
    
        
    }
    
    private static Singleton singleton;
    
    private static final AtomicReference<Singleton> INSTANCE = new AtomicReference();
    
    public static final Singleton getInstance() {
    
    
     for (; ; ) {
    
     
     	Singleton singleton = INSTANCE.get(); 
     	if (singleton != null) return singleton; 
     	INSTANCE.compareAndSet(null, new Singleton()); 
     	return INSTANCE.get(); 
         } 
     }
}

7. Enumeration

This writing method is similar in function to the common domain method, but it is more concise and provides a serialization mechanism without compensation. It absolutely prevents instantiation of this, even if it is against complex serialization or reflection attacks. time. Although this method has not been widely adopted, the single-element enumeration type has become the best method to implement Singleton and is recommended by the Effective Java author. It should be noted that it is not available in the case of inheritance.

public enum Singleton(){
    
    
	INSTANCE;
	
	public void method(){
    
    
	
	}
}

@Test
public void test() {
    
    
 Singleton.INSTANCE.method();
 }

Summary : Although the singleton mode is relatively simple, it is very common in development. In normal development, if you can ensure that this class is globally available without lazy loading, you can create it directly and call it externally. But if there are many classes, some of which need to be displayed after the user triggers a certain condition (game level), then lazy loading must be used.

Guess you like

Origin blog.csdn.net/MAKEJAVAMAN/article/details/115254924