Source code address of this chapter:
Github.com/Technicolor…
Definition:
Singleton pattern is a common software design pattern. It contains only one special class called a singleton in its core structure. The singleton ensures that there is only one instance of a class in the system. That is, a class has only one object instance.
The characteristics of:
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
Key points of the singleton pattern:
1. Private constructor
2. A private static reference to your own instance
3. a static public method that returns its own instance
Singletons are divided into two types based on the timing of instantiation:
One is hungry singleton, the other is lazy singleton.
A hanchian singleton instantiates an object to its reference when the singleton class is loaded. Lazy methods instantiate objects when they call the get instance method.
The code is as follows:
Hungry singleton (initialization is done when the class is loaded, so class loading is slow, but object retrieval is fast)
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(a){}
public static Singleton getInstance(a) {static, no synchronization (class is initialized when loading, no multithreading problems)returnsingleton; }}Copy the code
1) Private constructor 2) static private member — initialized at class loading 3) Public access point getInstance—– does not need to be synchronized because it was initialized at class loading and does not need to determine null
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.
Lazy singleton (not initialized when class is loaded)
public class Singleton {
private static Singleton singleton;
private Singleton(a){}
public static synchronized Singleton getInstance(a){ // Static, synchronous, public access point
if(singleton==null){
singleton = new Singleton();
}
returnsingleton; }}Copy the code
1) The constructor is defined as private —- and cannot fetch an object from another class. The constructor can only get its own object from the class itself. 2) The member variable is static and does not initialize —-. 3) public access points getInstance: public and synchronized —–public guarantee public access, synchronization guarantee multithreaded correctness (because class variables are not initialized at load time)
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.)
However, the implementation of the lazy Singleton above does not consider the issue of thread safety, because it is not thread safe. Multiple Singleton instances are likely to occur in a concurrent environment. To achieve thread safety, there are the following three ways, which are all modified from getInstance to ensure the thread safety of the lazy Singleton:
[1] Add synchronization to getInstance method:
public static synchronized Singleton getInstance(a) {
if (single == null) {
single = new Singleton();
}
return single;
}
Copy the code
The addition of synchronization on method calls, while thread-safe, affects performance by synchronizing every time, since synchronization is not required 99% of the time.
[2] **** singleton modeThere is also a more common form: the double lock form
public class Singleton{
private static volatile Singleton instance=null;
private Singleton(a){
//do something
}
public static Singleton getInstance(a){
if(instance==null) {synchronized(SingletonClass.class){
if(instance==null){
instance=newSingleton(); }}}returninstance; }}Copy the code
(1) Why use two if (singleton == null) in getInstance()?
A: Imagine a high concurrency situation where both threads AB pass the first if. If A grabs the lock, new an object, releases the lock, and then B grabs the lock again, if no second if judgment is made, thread B will create another object. It also ensures that synchronization is only done on the first call to the singleton, which is thread-safe and avoids the performance cost of synchronization every time.
(2) What is the role of volatile?
A: Thread A singleton = new Singleton(); thread A singleton = new singleton (); thread A singleton (); The assignment of the Singleton may be performed first. This operation actually creates an area of memory to store the object and then returns the reference to memory. After that, the Singleton will not be empty, but the actual initialization has not been performed. You see a singleton object that is not empty but incomplete (not initialized), so you need to add the volatile keyword to disable instruction reordering optimization to safely implement singletons.
This mode synchronizes content down to the inside of the IF, making execution more efficient. It does not need to be synchronized every time an object is fetched, but only the first time it is created.
This model of double judgment and synchronous way, than the first example of efficiency greatly, because if a single layer if judgment, in the case of a server allows, suppose you have one hundred threads, time for 100 * (synchronous judgment time + if judgment time), and if the double if judgment, 100 threads can judge if at the same time, The theory consumes only one if judgment time.
So if you’re dealing with high concurrency, and you’re in lazy mode, the best option is double judgment plus synchronization.
Static inner class:
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (a){}
public static final Singleton getInstance(a) {
returnLazyHolder.INSTANCE; }}Copy the code
It uses the classloader mechanism to ensure that instance initialization has only one thread, so it is thread safe and has no performance loss. This is better than the above [1] and [2], which not only realizes thread safety, but also avoids the performance impact caused by synchronization.
Registered singleton:
// 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 for protection
protected Singleton3(a){}
// Static factory method that returns a unique instance of this class
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(); }}return map.get(name);
}
// A schematic business approach
public String about(a) {
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.
The difference between hungry and lazy:
1. Initialization:
(1) Once the class is loaded, the singleton initialization is completed, to ensure that when getInstance, singleton is already exist.
(2) Lazy people initialize this singleton only when getInstance is called.
2. Thread safety:
(1) Hanesque is inherently thread-safe and can be used directly for multithreading without problems. Slacker style is itself non-thread-safe.
3. Performance:
(1) The 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 it is also faster on the first call because its resources have been initialized.
(2) Lazy, as the name implies, will be lazy load, the first use of the singleton will instantiate the object out, the first call to do initialization, if there is more work to do, there will be some performance delay, after the same as hungry.
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.
Testing:
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(a) {}private static volatile TestSingleton instance = null;
public static TestSingleton getInstance(a) {
if (instance == null) {
synchronized (TestSingleton.class) {
if (instance == null) {
instance = newTestSingleton(); }}}return instance;
}
public String getName(a) {
return name;
}
public void setName(String name) {
this.name = name;
}
public void printInfo(a) {
System.out.println("the name is "+ name); }}Copy the code
public class TMain {
public static void main(String[] args){
TestSingletonts1 = TestSingleton.getInstance();
ts1.setName("jason");
TestSingletonts2 = TestSingleton.getInstance();
ts2.setName("0539");
ts1.printInfo();
ts2.printInfo();
if(ts1 == ts2){
System.out.println("It's the same instance.");
}else{
System.out.println("Not the same instance created."); }}}Copy the code
Running results:
The name is0539 The name is0539 creates the same instanceCopy the code
Conclusion: The result is that the singleton pattern provides a unique point of access to an object for an object-oriented application, and the entire application shares an instance object regardless of what it does.
Summary:
Advantages of the singleton pattern:
1, there is only one object in memory, saving memory space.
2. Avoid frequent creation and destruction of objects to improve performance.
3. Avoid multiple occupation of shared resources.
4. Global access.
Disadvantages of the singleton pattern:
1. Scaling is difficult because the getInstance static function has no way to generate instances of subclasses. If you want to expand, you have to rewrite that class.
2. Implicit use causes unclear class structure.
3. The problem that causes the program to leak memory.
Applicable scenarios:
Because of the above advantages of the singleton pattern, it is a more popular design pattern used in programming. The following is a scenario using the singleton pattern:
1. Objects that need to be frequently instantiated and then destroyed.
2. Objects that take too much time or resources to create, but are often used.
3. In the case of resource sharing, avoid performance or loss caused by resource operation
4. Facilitate the communication between resources under the control of resources.
Notes for singleton mode:
Use only the methods provided by the singleton class to get a singleton object. Do not use reflection, otherwise a new object will be instantiated.
Do not do the dangerous thing of breaking a singleton class object from a static reference in the class.
Note thread-safety issues when multiple threads use singletons to use shared resources.
Some common questions about singleton patterns in Java:
Will singleton objects not used for long periods of time be collected by the JVM garbage collector
The JVM garbage collector does not reclaim a singleton unless the connection between a static reference to a singleton is artificially broken.
The criteria for uninstalling classes by JVM are as follows:
1, all instances of the class have been reclaimed, that is, there are no instances of the class in the Java heap.
2. The ClassLoader that loaded the class has been reclaimed.
3. The java.lang.Class object corresponding to this Class is not referenced anywhere, and there is no way to access its methods through reflection anywhere.
Only if all three conditions are met will the JVM unload classes during garbage collection. Obviously, the singleton class does not satisfy condition one, so the singleton class is not recycled.
Can multiple singletons occur in a SINGLE JVM
In the case of distributed systems, multiple classloaders, and serialization, there is no doubt that there will be multiple singletons. Can a singleton occur within the same JVM? Using the provided getInstance() method with a singleton only yields the same singleton, unless using reflection, a new singleton is returned.
The code is as follows:
Class c = Class.forName(Singleton.class.getName());
Constructor ct = c.getDeclaredConstructor();
ct.setAccessible(true);
Singleton singleton = (Singleton)ct.newInstance();
Copy the code
In this way, a new singleton is generated each time it runs. So when using the singleton pattern, be careful not to use reflection to create new singleton objects.
Is there an advantage to synchronizing on the getInstance() method or is it better to synchronize only the necessary blocks?
Because locking only makes sense when an instance is created, and then other times the instance is only read-only, it is better performance and a better choice to synchronize only the necessary blocks.
Disadvantages: It is only on the first call that two objects are generated and synchronization must be required. Once the singleton is not null, the system still incurs synchronization lock overhead, which is not worth the cost.
Can a singleton class be inherited
Singleton patterns can be divided into several types depending on when and how singleton instances are constructed. However, inheritance is not supported for singleton classes that provide instances through private constructors and static methods.
The singleton implementation of this pattern requires each concrete singleton class itself to maintain singleton instances and limit the generation of multiple instances. But you can use another way of implementing singletons to make them open to inheritance: registration singletons.
Original blog link:
Blog.csdn.net/jason0539/a…
Blog.csdn.net/a745233700/…