Address: http://www.haha174.top/article/details/253007

I. Concept:

The singleton pattern is a common design pattern in Java. There are several ways to write the singleton pattern, and three are mainly introduced here: lazy singleton, hungry singleton, and registered singleton. The singleton pattern has the following characteristics: 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. The singleton pattern ensures that there is only one instance of a class that is instantiated and made available to the entire system. In computer systems, thread pools, caches, log objects, dialogs, printers, and graphics card driver objects are often designed as singletons. All of these applications function more or less as resource managers. Each computer can have several printers, but only one Printer Spooler, to avoid two print jobs being output to the Printer at the same time. Each computer can have several communication ports, which should be centrally managed by the system to avoid one communication port being invoked by two requests at the same time. In short, the singleton pattern is chosen to avoid inconsistent states. Lazy singleton

// lazy singleton class. Instantiate yourself on the first call

public class Singleton {  
    private Singleton() {} private static Singleton single=null; Static factory method public static SingletongetInstance() {  
         if (single == null) {    
             single = new Singleton();  
         }    
        returnsingle; }}Copy the code

Singleton avoids being instantiated externally by limiting the constructor to private; within the same virtual machine scope, the only instance of a Singleton can be accessed only through the getInstance() method. (In fact, it is possible to instantiate classes with private constructors through Java reflection, which essentially invalidates all Java singleton implementations. This question is not discussed here, but let’s pretend that the reflection mechanism does not exist.) But above LanHanShi Singleton implementation does not consider the thread safety, it is thread safe, multiple concurrent environment could be in the Singleton instance, to realize thread safe, has the following three ways, are, for the modification of the getInstance this method ensures the LanHanShi Singleton thread safe, if you first contact the Singleton pattern, If you are not familiar with thread safety, you can skip the following three items to read hungry singletons, and come back to the thread safety issue later:

1. Add synchronization to getInstance

public static synchronized Singleton getInstance() {  
         if (single == null) {    
             single = new Singleton();  
         }    
        return single;  
}
Copy the code

2. Double-checked locking

public static Singleton getInstance() {  
        if (singleton == null) {    
            synchronized (Singleton.class) {    
               if(singleton == null) { singleton = new Singleton(); }}}return singleton;   
    }  
Copy the code

If you have two threads, A and B, and they both execute to the first if, both null, then they both execute the synchronized code block, assuming that A executes first, and then A has an instance, if the if is not checked then B will instantiate again and the singleton will be invalidated

3. Static inner classes

public class Singleton {    
    private static class LazyHolder {    
       private static final Singleton INSTANCE = new Singleton();    
    }    
    private Singleton (){}    
    public static final Singleton getInstance() {    
       returnLazyHolder.INSTANCE; }}Copy the code

This is better than both of the above, because it is thread-safe and avoids the performance impact of synchronization. Inner class loading: Inner classes (static or non-static) are loaded the first time they are used. The inner class is not loaded unless the outer class calls getInstance (), so it achieves the lazy effect; Then the inner class is loaded when it’s called, and the instance is initialized when it’s loaded; There will be no multithreading problems with this loading process! There is a mechanism for class loading called caching; It is cached after the first successful load. And you don’t load a class more than once

3. Hangry singleton

// The hunchman singleton class. Public class Singleton1 {private was instantiated when the class was initializedSingleton1() {} private static final Singleton1 single = new Singleton1(); Static factory method public static Singleton1getInstance() {  
        returnsingle; }}Copy the code

Hungry type has been created while class to create a static object for the use of system, won’t change, so naturally is thread-safe. 4. Registration singleton (negligible)

// Register the class name and fetch it directly from it next time. public class Singleton3 { private static Map<String,Singleton3> map = new HashMap<String,Singleton3>(); static{ Singleton3 single = new Singleton3(); map.put(single.getClass().getName(), single); } // The default constructor of protection is protectedSingleton3Public static Singleton3 getInstance(String name) {public static Singleton3 getInstance(String name) {if(name == null) {
            name = Singleton3.class.getName();
            System.out.println("name == null"+"--->name="+name);
        }
        if(map.get(name) == null) { try { map.put(name, (Singleton3) Class.forName(name).newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }}returnmap.get(name); } // A generic business method public Stringabout() {    
        return "Hello, I am RegSingleton."; } public static void main(String[] args) { Singleton3 single3 = Singleton3.getInstance(null); System.out.println(single3.about()); }}Copy the code

A registered singleton actually maintains a set of instances of a singleton class, stored in a Map (registry), returned directly from the Map for registered instances, and registered and returned for unregistered instances.

I marked the register singleton as ignorable because, as I understand it, it is used less often, and the internal implementation is actually a hunchman singleton because of the static method block, whose singleton is instantiated when the class is loaded.

The difference between hungry and lazy

From the name, hungry and lazy,

Once the class is loaded, it initializes the singleton so that when getInstance is loaded, the singleton already exists,

Lazy people are lazy and only initialize the singleton when getInstance is called.

In addition, the following two ways are distinguished from the following two points:

1. Thread safety:

Hungriness is inherently thread-safe and can be used directly with multiple threads without problems,

Lazy style itself is not thread-safe. There are several ways to achieve thread-safe implementation, namely, 1, 2, and 3 above. The three implementations have some differences in resource loading and performance.

2. Resource loading and performance:

Hanchian instantiates a static object at the same time the class is created. Regardless of whether the singleton is used later, it takes up some memory, but is correspondingly faster on the first call because its resources have already been initialized.

Slacker, as the name implies, loads lazily, instantiates the object the first time it’s used, initializes it the first time it’s called, and if it’s a lot of work, there’s a bit of a performance delay, and then it’s hunchback.

There are some differences between implementations 1, 2, and 3.

The first option is to add synchronization to method calls, which is thread-safe, but requires synchronization every time. After all, synchronization is not required 99% of the time.

Second, null checks are done twice in getInstance to ensure that synchronization is performed only on the first call to the singleton, which is also thread-safe and avoids the performance penalty of synchronizing every time

The third one uses the classloader mechanism to ensure that instance is initialized with only one thread, so it is thread-safe and has no performance loss, so GENERALLY I prefer to use this one.

What is thread safety?

If your code is in a process that has multiple threads running at the same time, those threads may be running the code at the same time. If the result of each run is the same as the result of a single thread run, and the values of other variables are the same as expected, it is thread-safe.

In other words, an interface provided by a class or program is atomic to threads, or switching between threads does not result in an ambiguous execution of the interface, which means we do not have to worry about synchronization, which is thread-safe.

Five, the application of

Here is an example of the use of a singleton class. In lazy style, double-checked locking is used to ensure thread safety:

public class TestSingleton {
	String name = null;

        private TestSingleton() {
	}

	private static volatile TestSingleton instance = null;

	public static TestSingleton getInstance() {
           if (instance == null) {  
             synchronized (TestSingleton.class) {  
                if(instance == null) { instance = new TestSingleton(); }}}return instance;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void printInfo() {
		System.out.println("the name is "+ name); }}Copy the code

Volatile is used to declare singletons. Since synchronized provides atomicity, order, and visibility in multiple threads, it is necessary to use volatile. Instance = new Instance() constructor is A non-atomic operation that generates multiple bytecode instructions after compilation. Due to JAVA instructions reordering, instance assignment may be performed first. Instance is not empty, but the actual initialization has not been performed. If thread B enters at this point, it will see an instance object that is not empty but incomplete. Therefore, the volatile keyword is needed to prevent instruction reordering optimization and safely implement singletons

Six conclusions

The results show that the singleton pattern provides a unique point of access to an object for an object-oriented application, and that the entire application shares an instance object regardless of what function it implements.

For several implementations of the singleton pattern, know the difference between hungry and lazy, thread safety, resource loading timing, and the nuances of the three ways lazy implements thread safety.

Reprinted from: author: jason0539 blog: http://blog.csdn.net/jason0539 (reprint please indicate the source)

Welcome to follow, more benefits