The singleton pattern has the following characteristics:
1. A singleton class can only have 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, and it instantiates itself and provides this instance to the entire system. In computer systems, thread pools, caches, log objects, dialog boxes, printers, and graphics card driver objects are often designed as singletons. These applications all have more or less the functionality of resource managers. Each computer can have several printers, but there can only be one Printer Spooler to prevent two print jobs from being output to the printer at the same time. Each computer can have several communication ports, and the system should centrally manage these communication ports to prevent one communication port from being called by two requests at the same time. In short, the purpose of choosing the singleton mode is to avoid inconsistent states and avoid long-term policies.
First, let’s look at a classic singleton implementation.
Copy the code code as follows:
public class Singleton {
private static Singleton uniqueInstance = null;
private Singleton() {
// Exists only to defeat instantiation.
}
public static Singleton getInstance() { if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// Other methods...
}
Singleton avoids the class from being instantiated externally by limiting the construction method to private. Within the scope of the same virtual machine, the only instance of Singleton can only be accessed through the getInstance() method. (In fact, it is possible to instantiate a class with a private constructor through the Java reflection mechanism, which will basically invalidate all Java singleton implementations. This issue will not be discussed here. Let’s pretend that the reflection mechanism does not exist. .)
However, the above implementation does not consider thread safety issues. The so-called thread safety means: if there are multiple threads running at the same time in the process where your code is located, these threads may run this code at the same time. If the results of each run are the same as those of single-threaded runs, and the values of other variables are the same as expected, it is thread-safe. In other words: the interface provided by a class or program is an atomic operation for threads or switching between multiple threads will not cause ambiguity in the execution results of the interface, which means that we do not need to consider synchronization issues. Obviously the above implementation does not meet the requirements of thread safety, and multiple Singleton instances are likely to appear in a concurrent environment.
Copy the code code as follows:
//Hungry-style singleton class. It has been instantiated by itself when the class is initialized.
public class Singleton1 {
//Private default constructor
private Singleton1() {}
//Already instantiated by itself
private static final Singleton1 single = new Singleton1();
//static factory method
public static Singleton1 getInstance() {
return single;
}
}
//Lazy singleton class. Instantiate when called for the first time
public class Singleton2 {
//Private default constructor
private Singleton2() {}
//Note, there is no final here
private static Singleton2 single=null;
//static factory method
public synchronized static Singleton2 getInstance() {
if (single == null) {
single = new Singleton2();
}
return single;
}
}