Teacher Ma Bingbing’s Computer Network Notes 1: Discussion of Singleton Pattern

The singleton mode means that users are not allowed to create their own objects without constructing methods, obtain objects through static methods, and obtain the same instance.
case1:

public class DCLDemoCase1 {
    
    
	private static DCLDemoCase1 instance=new DCLDemoCase1();
	private DCLDemoCase1() {
    
    };
	public static DCLDemoCase1 getInstance() {
    
    
		return instance;
	}
	private int m=1;
	public void m() {
    
    
		System.out.println(m);
	}
}
public static void main(String[] args) {
    
    
		DCLDemoCase1 instance2 = DCLDemoCase1.getInstance();
		DCLDemoCase1 instance3 = DCLDemoCase1.getInstance();

		System.out.println(instance2==instance3);
	}

Test result: true. Both objects are identical.
Case2: The newly created object in the statement has not been used yet. Create the object directly. Sometimes it is a waste of time to create an object. Can you put the creation process in a method and create it when needed
? So there is a second way of writing:private static DCLDemoCase1 instance=new DCLDemoCase1();

public class DCLDemoCase2 {
    
    
	private static DCLDemoCase2 instance;
	private int m=1;
	private DCLDemoCase2() {
    
    };
	public static synchronized DCLDemoCase2 getInstance() {
    
    
		if(instance==null) {
    
    
			try {
    
    
				Thread.sleep(1);
			} catch (InterruptedException e) {
    
    
				e.printStackTrace();
			}
			instance=new DCLDemoCase2();
		}
		return instance;
	}
		public void m() {
    
    
		System.out.println(m);
	}
	}

The test can achieve the running effect in multi-threaded situations, and they are all the same object.
Interlude:
But I also found that it is indeed sleeping without Thread.sleep(1):

public class DCLDemoCase2 {
    
    
	private static DCLDemoCase2 instance;
	private int m=1;
	private DCLDemoCase2() {
    
    };
	public static DCLDemoCase2 getInstance() {
    
    
		if(instance==null) {
    
    
			instance=new DCLDemoCase2();
		}
		return instance;
	}
		public void m() {
    
    
		System.out.println(m);
	}
	}

It will also achieve the expected effect. In theory, different objects will appear. It may be true that in this case, different threads will not enter the if at the same time to create different objects.

Then case2
case3:
But this directly locks the entire method. This kind of lock is too thick. Among the lock optimizations, one is lock refinement.

public class DCLDemoCase2 {
    
    
	private static DCLDemoCase2 instance;
	private int m=1;

	private DCLDemoCase2() {
    
    
	};

	public static DCLDemoCase2 getInstance() {
    
    
		if (instance == null) {
    
    
			synchronized (DCLDemoCase1.class) {
    
    
				instance = new DCLDemoCase2();
			}
		}
		return instance;
	}
		public void m() {
    
    
		System.out.println(m);
	}
	}

It is found that different objects will appear under multi-threading, which cannot achieve the effect of single thread.
This is because: each thread's initial instance=null initially, so several threads will enter if(instance==null), and they will get different objects.
case4:
double lock dcl

public class DCLDemoCase4 {
    
    
	private static DCLDemoCase4 instance;
private int m=1;
	private DCLDemoCase4() {
    
    
	};

	public static synchronized DCLDemoCase4 getInstance() {
    
    
		if (instance == null) {
    
    
			synchronized (DCLDemoCase1.class) {
    
    
				if(instance==null) {
    
    
				instance = new DCLDemoCase4();
				}
			}
		}
		return instance;
	}
		public void m() {
    
    
		System.out.println(m);
	}
	}

When multiple threads enter the first empty judgment, then even if the first thread creates the object and the instance is not empty, these threads are eligible to enter the lock (synchronized) to create the object. However, when the first thread enters the lock The object has been created in the object and the instance has been assigned a value. The instance is not empty. Other threads (except the first thread after entering the first null judgment) can only enter the lock, but cannot overcome the second null judgment and cannot create new threads. .
Case5:
The program appears to be perfect, but does the instance need to be modified volatile?
Really needed.
Insert image description here
There are roughly 3 steps to create an object (only roughly):) (1) Open a piece of memory in the heap [new] (2) Construction method...initialization [invokespecial] (3) Object variable points to this memory [astore]

**Then this may be the case: ** The instructions are reordered
to open up memory in thread 1. The default value of m in the class is 0, and then it is directly assigned to the class object t. There are two threads, and the first thread comes first. Instruction reordering occurs, and there is no time to assign a value to m. The second thread comes to judge that t is not empty and uses it directly. What the second thread gets is an incorrect object instance.

package doubleCheckLock;

public class DCLDemoCase5 {
    
    
	private static volatile DCLDemoCase5 instance;
	private int m=1;
	private DCLDemoCase5() {
    
    
	};

	public static synchronized DCLDemoCase5 getInstance() {
    
    
		if (instance == null) {
    
    
			synchronized (DCLDemoCase1.class) {
    
    
				if(instance==null) {
    
    
				instance = new DCLDemoCase5();
				}
			}
		}
		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(DCLDemoCase2.getInstance().hashCode());
			}).start();
		}
	}
}

Here volatile means that instruction reordering is prohibited.

Supongo que te gusta

Origin blog.csdn.net/qq_52605986/article/details/117306059
Recomendado
Clasificación