Design Patterns (1) - Singleton Pattern (Singleton)
The simplest design pattern, this pattern involves a single class that is responsible for creating its own objects while ensuring that only a single object is created. This class provides a way to access its only object, directly, without instantiating an object of the class. This class can only new out of one object.
- advantage:
- There is only one instance in memory, which reduces memory overhead, especially when instances are created and destroyed frequently (such as the cache of the home page of the School of Management).
- Avoid multiple occupation of resources (such as write file operations).
- Disadvantages: No interface, no inheritance, conflicts with the principle of single responsibility, a class should only care about the internal logic, not how to instantiate it outside.
how to create
Hungry Chinese
I think it is the simplest way to write, and the shortcomings are not prominent.
Create a static object in the class and use public methods to access the object.
- Advantages: There is no lock, and the execution efficiency will be improved. thread safe.
- Disadvantages: The class is initialized when the class is loaded, which wastes memory.
//Hungry Chinese public class Mgr { //Create a singleton object private static final Mgr mgr = new Mgr(); //constructor private private Mgr() { } //Access objects through public methods public static Mgr GetMgr() { return mgr; } public static void main(String[] args) { //Create a singleton object Mgr mgr = Mgr.GetMgr(); } }
lazy
thread unsafe
Determine whether the object is instantiated when it is instantiated,
If not, create the object,
If there is, return the object
/* lazy Determine whether the object is instantiated when it is instantiated, If not, create the object, If there is, return the object */ public class Mgr { //The final keyword cannot be used here, otherwise it cannot be changed public static Mgr mgr = null; private Mgr() { } //Check if mgr is empty public static Mgr getMgr() { if(mgr==null) { mgr = new Mgr(); return mgr; } else return mgr; } public static void main(String[] args) { //Create a singleton object Mgr mgr = Mgr.getMgr(); } }
But this way of writing is not safe. When using multi-threading, if(mgr==null) is executed, and the object has not been created, another thread also executes if(mgr==null), so it leads to the creation of multiple objects.
import static java.lang.Thread.sleep; /* lazy Determine whether the object is instantiated when it is called, If not, create the object, If there is, return the object */ public class Mgr { //The final keyword cannot be used here, otherwise it cannot be changed public static Mgr mgr = null; private Mgr() { } //Check if mgr is empty public static Mgr getMgr() { if(mgr==null) { //There is an operation delay here for a fraction of the time 1 try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } mgr = new Mgr(); return mgr; } else return mgr; } public static void main(String[] args) { //Create a singleton object from multiple threads for(int i=1; i<100; i++) { new Thread(new Runnable() { @Override public void run() { Mgr mgr = Mgr.getMgr(); System.out.println(mgr); } }).start();} } }
It can be seen that not all of the output addresses are consistent.
Lazy (locked)
Solve lazy thread-safety issues
Lock before getMgr() to make it a synchronized method
import static java.lang.Thread.sleep; /* lazy Determine whether the object is instantiated when it is called, If not, create the object, If there is, return the object */ public class Mgr { public static Mgr mgr = null; private Mgr() { } //Check if mgr is empty public static synchronized Mgr getMgr() { if(mgr==null) { try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } mgr = new Mgr(); return mgr; } else return mgr; } public static void main(String[] args) { //Create a singleton object from multiple threads for(int i=1; i<100; i++) { new Thread(new Runnable() { @Override public void run() { Mgr mgr = Mgr.getMgr(); System.out.println(mgr); } }).start();} } }
double lock
The efficiency of the synchronization method is too low, so there is a way to add double locks.
The two judgments here are necessary, because there may be multiple threads passing the first layer judgment.
import static java.lang.Thread.sleep; /* lazy Determine whether the object is instantiated when it is called, If not, create the object, If there is, return the object */ public class Mgr { public static Mgr mgr = null; private Mgr() { } //Check if mgr is empty public static Mgr getMgr() { if(mgr==null) { synchronized (Mgr.class) { //double lock if(mgr==null) { synchronized (Mgr.class) { //double lock try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } mgr = new Mgr(); } } } return mgr; } else return mgr; } public static void main(String[] args) { //Create a singleton object from multiple threads for(int i=1; i<100; i++) { new Thread(new Runnable() { @Override public void run() { Mgr mgr = Mgr.getMgr(); System.out.println(mgr); } }).start();} } }
static inner class
This method does not produce garbage objects and does not produce thread safety.
JVM guarantees: static classes are loaded only once. And the inner class is not loaded when the outer class is loaded.
public class Mgr { private Mgr() { } private static class MgrHolder { private static final Mgr mgr = new Mgr(); } //Check if mgr is empty public static Mgr getMgr() { return MgrHolder.mgr; } public static void main(String[] args) { Mgr mgr = Mgr.getMgr(); } }
enumeration singleton
Can prevent deserialization
public enum Mgr{ mgr; }