Single instance creation. There are many examples on the Internet. I just take notes here. Maybe it's not more detailed than others. It's mainly to make some cloud notes for myself
1. hungry man
public class Ehan { //1. Provide a static instance private final static Ehan instance = new Ehan(); //2. Privatization constructor private Ehan(){} //Provide a method to obtain an external instance public static Ehan getInstance(){ return instance; } }
Test:
public static void main(String[] args){ for (int i = 0; i < 100; i++) { new Thread(() -> { Ehan obj = Ehan.getInstance(); System.out.println(obj.hashCode()); }, "thread" + i).start(); } }
Result:
All hashcode s are the same, indicating the same instance
Advantages: thread safe
Disadvantages: when a class is loaded, it will be instantiated (if other static properties or static methods of the class are used, it will be instantiated, but in fact, I may not need it to be instantiated). If I do not use this class later, it is a waste
2. slacker
public class LanHan { //1. Define a static variable private static LanHan instance; //2. Privatization constructor private LanHan(){} //3. Provide a method to obtain an external instance public synchronized static LanHan getInstance(){ if(instance == null){ instance = new LanHan(); } return instance; } }
synchronized on getInstance() cannot be saved, which may cause problems
The test method still uses the above test method, just change the class
Modify the getInstance() method, kill synchronized, and add a sleep before creation to simulate other operations, which takes a little time
public static LanHan getInstance(){ if(instance == null){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } instance = new LanHan(); } return instance; }
Results:
There are different results here. It is found that instead of creating a single instance, different instances are created
This is because there is no lock on the method, and different threads can come in. Then many threads stop at the place where they sleep, and the later threads catch up and also sleep
When hibernation is complete, continue to execute the code and create the instance
Advantages and disadvantages of lazy mode:
Advantage:
1. It overcomes the problem of loading and creating in hungry mode. When the getInstance() method is called, the instance will be created. It is equivalent to loading on demand
2. Thread safety
Disadvantages:
1. Every time getInstance() is called, a null judgment will be performed
2. getInstance() method is locked. When it is called concurrently, it needs to be queued. When one thread releases the lock, other threads need to compete for the lock
3. Double judgment
/** * double checked locking **/ public class DCL { //1. Provide a static reference private static volatile DCL instance; //2. Privatization constructor private DCL(){} //3. Provide an external access instance interface public static DCL getInstance(){ if(instance == null){ synchronized (DCL.class){ if(instance == null){ instance = new DCL(); } } } return instance; } }
Result:
Judge again in the lock to ensure thread safety
Similarly, make a small change to the getInstance() method here:
public static DCL getInstance() { if (instance == null) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (DCL.class) { // if(instance == null){ instance = new DCL(); // } } } return instance; }
Here, I will comment out the judgment in the lock, and add a sleep outside the lock. Let's see if it works:
In the same way,
Article 1 when a thread comes in, it is empty √ and goes to sleep
When the second thread comes in, it is empty √ to enter sleep. The first thread may still be in sleep, let alone create an instance
......
Some logic processing may take time. When an instance is created, it may not only need new processing, but also need some logic processing before. It will take a little time, similar to the sleep effect here
So we need to add a null judgment in the lock. Because the code in the lock can only be executed by one thread, even if other logic processing takes time, the above situation will not occur\
Until this thread is created and another thread comes in, you can judge that the instance has been created
4. Internal static class mode
public class Inner { //1. Privatization constructor private Inner(){} //2. Static class private static class InnerBuilder{ private final static Inner instance = new Inner(); } //3. Provide a way to get an instance public static Inner getInstance(){ return InnerBuilder.instance; } }
In all methods, we can't save the step of privatizing the constructor. Otherwise, we can create it through the way of new, which is not a single example
Result:
This method is recommended
Advantages:
1. Thread safety
2. Simple code
3. No need to add lock (there is an initialization lock, but it is not added artificially)
4. Delay loading (internal classes can only be loaded when they are loaded by external classes)
5. enumeration class
public enum EnumObj { INSTANCE; }
I haven't done it in this way
In general, the use of internal static classes on the line