Post location Zhi: http://www.iteye.com/topic/652617
I learned the notes made by Singleton pattern and shared them with cainiao like me. Hope to help cainiao a little bit.
I have referred to: Balan's article javasingleton practical tutorial (with source code)
Address: http://balan.iteye.com/blog/164873
I. Definition
Singleton pattern: ensures that a class has only one instance and provides a global access point.
This definition contains two meanings:
First, we design a class as a separate instance managed by ourselves. At the same time, we must avoid other classes from generating instances on our own. To obtain a single instance, the singleton class is the only way.
Second, we must provide global access points for this instance: When you need an instance, you can query the instance type and it will return a single instance to you.
Note: The Singleton mode ensures that a class has only one instance, which means that only one instance can be in a specific system range. In some cases, Singleton cannot be used for singleton. If multiple Singleton objects are simultaneously loaded by different class loaders; in distributed systems such as ejbs, you should also pay attention to this situation because ejbs are cross-server and cross-JVM.
1. In a framework container: such as the Spring IoC container, You can ensure the uniqueness of the instance in the container through configuration.
2. In addition, the uniqueness of an instance can be guaranteed when a class is loaded by a single JVM or a single class loader.
If they are in two class loaders or JVM, they may have the opportunity to create their own single instance, because each class loader defines a namespace, if there are more than two class loaders, different class loaders may load the same class. From the perspective of the whole program, the same class will be loaded multiple times. If this happens in a singleton instance, multiple Singleton instances will coexist. So if your program has multiple classes loaded and you are using the singleton mode, be careful. One solution is to specify the Class Loader (specify the same class loader) for the singleton class ).
Ii. usefulness
Some objects actually only need one, such as threadpool, cache, registry, and driver of the device. In fact, the objects of these classes can only have one instance. If multiple instances are created, many problems may occur, such: abnormal Program behavior, excessive use of resources, and inconsistent results. The javasingleton mode provides us with the possibility of such implementation. Singleton also saves memory because it limits the number of instances and facilitates Java garbage collection ). We often see that the class loader in the factory mode is also implemented in the singleton mode, because the loaded class actually belongs to the resource.
Iii. Several common Java Singleton Modes
1 ). Create an instance immediately without delaying instantiation
1. Use global variables
Java code
- // Singleton with final field
- Public class Singleton {
- Public static final Singleton uniqueinstance = new Singleton ();
- Private Singleton (){
- }
- //... Remainder omitted
- }
In this method, the public static member is a final domain (which always contains the same object reference ). The private constructor is called only once to instantiate the public static final domain Singleton. uniqueinstace. Due to the lack of public or protected constructors, all guarantee the global uniqueness of singleton: Once the singleton class is instantiated, only one Singleton instance exists-Not many or many. Any behavior of a programmer using this Singleton class cannot be changed.
2. Use public static factory methods
Java code
- // Singleton with static Factory
- Public class Singleton {
- Private Static Singleton uniqueinstance = new Singleton ();
- Private Singleton (){
- }
- Public static Singleton getinsingleton (){
- Return uniqueinstance;
- }
- //... Remainder omitted
- }
The second method provides a public static factory method instead of a public static final domain. Using this method, we rely on JVM to immediately create a unique instance of this class when loading this class. Before JVM ensures that any thread accesses the uniqueinstance static variables, you must first create this instance.
2 ). Using delayed instantiation (using public static factory methods)
1. Non-thread-safe
Java code
- Public class Singleton {
- Private Static Singleton uniqueinstance;
- Private Singleton (){
- }
- Public static Singleton getinsingleton (){
- If (uniqueinstance = NULL ){
- Uniqueinstance = new Singleton ();
- }
- Return uniqueinstance;
- }
- //... Remainder omitted
- }
First, we use a static variable uniqueinstance to record the unique instance of the singleton class. When we want to use its instance, if it does not exist, the private constructor is used to generate a singleton class instance and assign it to the uniqueinstance static variable. If we don't need this instance, it will never be generated. This is "lazy instantiaze )". However, the preceding program cannot guarantee a single instance in a multi-threaded environment. The analysis is as follows:
Time Point |
Thread 1 |
Thread 2 |
Uniqueinstance Value |
1 |
Thread 1 and 2 simultaneously access the singleton. getinstance () method |
|
|
2 |
Enter the singleton. getinstance () method |
|
Null |
3 |
|
Enter the singleton. getinstance () method |
Null |
4 |
Execute if (uniqueinstance = NULL) Judgment |
|
Null |
5 |
|
Execute if (uniqueinstance = NULL) Judgment |
Null |
6 |
Run uniqueinstance = new Singleton () |
|
Singleton1 |
7 |
|
Run uniqueinstance = new Singleton () |
Singleton2 |
8 |
Execute return uniqueinstance; |
|
Singleton1 |
9 |
|
Execute return uniqueinstance; |
Singleton2 |
As shown in the preceding analysis, two Singleton instances have been generated.
2. Multi-thread secure
Java code
- Public class Singleton {
- Private Static Singleton uniqueinstance;
- Private Singleton (){
- }
- Public synchronized static Singleton getinsingleton (){
- If (uniqueinstance = NULL ){
- Uniqueinstance = new Singleton ();
- }
- Return uniqueinstance;
- }
- //... Remainder omitted
- }
Add the synchronized keyword to the getinstance () method, that is, lock the getinstance () method thread to force only one thread to enter this method at a time, this will solve the above multi-thread disaster. However, the locking synchronization method may cause a significant reduction in program execution efficiency. If your program has high performance requirements and your getinstance () method is frequently called, this design may not meet the program requirements. In fact, this lock synchronization method is used in this case, there are some problems, because for the singleton class, only when the getinstance () method is executed for the first time, you need to lock the method for synchronization, because once the uniqueinstance variable is set for the first time, you no longer need to synchronize this method. Every time this method is called, synchronization becomes a burden.
3. Use "double check and lock" to reduce the use of synchronization in the getinstance () method:
Java code
- Public class Singleton {
- // The volatile keyword ensures that multiple threads correctly process the uniqueinstance variable when the uniqueinstance variable is initialized to a singleton instance
- Private volatile static Singleton uniqueinstance;
- Private Singleton (){
- }
- Public static Singleton getinsingleton (){
- If (uniqueinstance = NULL) {// check the instance. If the instance does not exist, synchronize the code area.
- Synchronized (singleton. Class) {// lock it to prevent both threads from entering the synchronization code zone at the same time
- If (uniqueinstance = NULL) {// double check is very important. If two threads access the synchronization code area at the same time, an instance is generated after the first thread accesses the synchronization code area; when the second thread that has been waiting for the getinstance method enters the synchronization code area, a new instance is generated.
- Uniqueinstance = new Singleton ();
- }
- }
- }
- Return uniqueinstance;
- }
- //... Remainder omitted
- }
There is a deep article on double-checked locking: http://www.cs.umd.edu /~ API/Java/MemoryModel/doublecheckedlocking.html
3. Sington class serialization
To change the singleton class to serializable, it is not enough to implement the serializable interface only. To maintain Singleton, you must provide a readresolve method for the Singleton class. Otherwise, a serialized instance will generate a new instance for each deserialization. Singleton is no exception.
As follows:
Java code
- Import java. Io. fileinputstream;
- Import java. Io. fileoutputstream;
- Import java. Io. objectinputstream;
- Import java. Io. objectoutputstream;
- Import java. Io. objectstreamexception;
- Import java. Io. serializable;
- // Singleton with final field
- Public class Singleton implements serializable {
- Private Static final long serialversionuid = 5765648836796281035l;
- Public static final Singleton uniqueinstance = new Singleton ();
- Private Singleton (){
- }
- //... Remainder omitted
- Public static void main (string [] ARGs) throws exception {
- // Serialization
- Objectoutputstream = new objectoutputstream (New fileoutputstream ("D: \ singleton. OBJ "));
- Singleton = singleton. uniqueinstance;
- Objectoutputstream. writeobject (Singleton );
- Objectoutputstream. Close ();
- // Deserialization
- Objectinputstream = new objectinputstream (New fileinputstream ("D: \ singleton. OBJ "));
- Singleton singleton2 = (Singleton) objectinputstream. readobject ();
- Objectinputstream. Close ();
- // Compare the original Instance
- System. Out. println (Singleton = singleton2 );
- }
- }
The output result is: false.
The solution is to add readresolve () to the singleton class:
Java code
- // The readresolve method maintains Singleton attributes.
- Private object readresolve () throws objectstreamexception {
- Return uniqueinstance;
- }
Test again: the output result is true.
After deserialization, the newly created object will call this method first. The object reference returned by this method is returned, replacing the newly created object. Essentially, this method ignores the newly created object and returns the instance created during class initialization.