The singleton mode can be very simple, all it takes is one class to complete (see this chapter poor UML diagram). However, if the "number of objects created and when to create" the two points, the singleton pattern can be quite complex, more complex than the first five modes combined, for example, a DCL double lock detection (double
Checked
locking), involving multiple classloader (ClassLoader), involves a cross-JVM (cluster, remote EJB, etc.), when the singleton object is destroyed and rebuilt.
Objective:
You want the object to create only one instance and provide a global access point.
Figure 6.1 UML diagram of a singleton pattern
The structure is simple, but there is a situation;
1. You can return one and only one object at a time from getinstance ().
2. In the case of resource sharing, getinstance () must adapt to multi-threaded concurrent access.
3. Improve access performance.
4. Lazy loading (lazy load) is constructed when needed.
first implement the Singleton pattern A in 1:
4. Public classSingletona {5. 6./**7. * Singleton Object Example 8. */9.Private StaticSingletona instance =NULL; 10. 11. Public StaticSingletona getinstance () {12.if(Instance = =NULL) {// LineInstance =NewSingletona ();// Line14. } 15.returninstance; 16. } 17.}
This writing we put four point requirements from the top down detection, found that the 2nd time there is a problem, assuming such a scenario: two threads concurrent call Singleton.getinstance (), assuming that the line Cheng first determine whether the instance is null, both the code 12 Enter the location of line 13. As soon as the decision is complete, the JVM switches the CPU resources to thread two, and because the line Cheng has not yet been executed, the instance is still empty, so thread two performs the new Signleton () operation. After a moment, the line Cheng is awakened, and it is still performing the new Signleton () operation. So the singleton pattern of this design does not meet the 2nd requirement.
Here we go.
implement 2 in the singleton mode B:
4. Public classsingletonb {5. 6./**7. * Singleton Object Example 8. */9.Private Staticsingletonb instance =NULL; 10. 11. Public synchronized Staticsingletonb getinstance () {12.if(Instance = =NULL) { Instance =Newsingletonb (); 14. } 15.returninstance; 16. } 17.}
Compared to the singleton a only in the method of a synchronized modifier, can now guarantee that the problem is not the thread. But there's a big (at least time-consuming) performance problem here. In addition to executing the SINGLETONKERRIGANB constructor for the first call, each subsequent call returns the instance object directly. Returning an object this is a time-consuming operation, with most of the time spent on the synchronized modifier's synchronous preparation, which is therefore not a cost-effective performance.
The Synchironized keyword can be added to the code block in addition to the method:
Private StaticObject Instance_lock =NewObject (); Public StaticHello getinstance (context context) {synchronized(instance_lock) {if(INSTANCE = =NULL) {INSTANCE=NewHello (); }} Mcontext=context; returnINSTANCE; }
Implement 3 single-case mode C:
4. Public classSingletonc {5. 6./**7. * Singleton Object Example 8. */9.Private StaticSingletonkerrigand instance =NULL; 10. 11. Public StaticSingletonc getinstance () {12.if(Instance = =NULL) { 13.synchronized(Singletonc.class) { 14.if(Instance = =NULL) { Instance =NewSingletonc (); 16. } 17. } 18. } 19.returninstance; 20. } 21.}
It seems that this has reached our requirement that, in addition to the first creation of an object, the other accesses are returned in the first if, and therefore do not go to the synchronization block. Is it perfect?
Let's take a look at this scenario: assuming that the thread executes to instance = new Singletonkerrigand (), it looks like a sentence, but in fact it's not an atomic operation (atomic manipulation means that the statement is either executed or not executed, It is not possible to perform half of this scenario). In fact, there are many non-atomic operations in high-level languages, and we just have to look at the corresponding assembly code that was compiled and executed in the JVM, and this sentence was compiled into 8 assembly instructions, roughly doing 3 things:
1. Allocate memory to the instance of Kerrigan.
2. Initialize the Kerrigan constructor
3. Point the instance object to the allocated memory space (note that this step instance is not null).
However, because the Java compiler allows the processor to execute in a random order (Out-of-order), and JDK1.5 jmm (Java Memory Medel) before the cache, register to the main memory write-back order of the provisions, the above 2nd and 3rd order is not guaranteed, That is, the execution order may be 1-3-2, if it is the latter, and after 3 execution, 2 is not executed, is switched to the thread two, this time instance because it has been in line one to execute the 3rd, instance is already non-empty, So thread two take instance directly, then use, and then logically error, and this difficult to track difficult to reproduce errors estimated that the debugging last week may not be able to find out, is really a coffee table cup.
It is not entirely true that the DCL is written in a form that is recommended in a number of technical books, textbooks (including books based on JDK1.4 versions). It is true that the DCL is feasible in some languages, such as the C language, depending on whether the order of 2, 3 steps is guaranteed. After JDK1.5, the authorities have noticed this issue, so the JMM is adjusted and the volatile keyword is materialized, so if the JDK is a 1.5 or later version, you only need to change the definition of instance to "private volatile static Singletonkerrigand instance = null; " It is guaranteed that every time the instance is read from the main memory, it is possible to use the DCL notation to complete the singleton mode. Of course, volatile is more or less likely to affect performance, and most importantly we have to consider JDK1.42 as well as previous versions, so the improvement of the single-instance pattern in this article continues.
The code is getting more and more complicated, so let's get back to basics, according to JLS (Java Language specification), a class is initialized only once in a classloader, which is guaranteed by the JVM itself, Then throw the initialized instance to the JVM.
Implement 4 single-case mode D:
4. Public classSingletond {5. 6./**7. * Singleton Object Example 8. */9.Private StaticSingletond instance =NewSingletond (); 10. 11. Public StaticSingletond getinstance () {12.returninstance; 13. } 14.}
This type of writing does not occur concurrency problems, but it is a hungry man-style, after ClassLoader loaded class Kerrigan instance will be created the first time, a hungry man style of creation in some scenarios will not be used: for example, the creation of the instance is dependent on parameters or configuration files, You must call a method before getinstance () to set the parameter to it, so that the single-instance notation cannot be used.
Available with parameter singleton mode e:
4. Public classSingletone {5. 6.Private Static classSingletonholder {7./**8. * Singleton Object Example 9. */10.Static FinalSingletone INSTANCE =NewSingletone (); 11. } 12. 13. Public StaticSingletone getinstance () {14.returnsingletonholder.instance; 15. } 16.}
This notation still uses the JVM itself to ensure thread safety, and since Singletonholder is private, there is no way to access it except for getinstance (), so it is lazy, and does not synchronize while reading instances, no performance flaws , and does not rely on JDK versions.
Of course, the user constructs the singleton object in other way, if the designer does not want this situation to happen, then needs to do the evasion. Other ways to create a singleton example are:
1. Direct new Singleton Object
2. Constructing a singleton object by reflection
3. Construct a singleton object by serialization.
In the first case, we typically add a private or protected constructor so that the public constructor is not automatically added, so only the static method inside can be called, and the object cannot be created with new.
For the second case, reflection can use the Setaccessible method to break the limits of private, we need to do the 1th job, but also in Reflectpermission ("Suppressaccesschecks") Use the Checkpermission method of the Security Manager (SecurityManager) under Permissions to limit this breakthrough. In general, do not really do these things, are through the application server for background configuration implementation.
For the third case, if the singleton object is necessary to implement the Serializable interface (rarely), then the Readresolve () method should be implemented at the same time to ensure that the original object is obtained when deserializing.
Ultimate Single-case mode F:
4. Public classSingletonfImplementsSerializable {5. 6.Private Static classSingletonholder {7./**8. * Singleton Object Example 9. */10.Static Finalsingletonf INSTANCE =Newsingletonf (); 11. } 12. 13. Public Staticsingletonf getinstance () {14.returnsingletonholder.instance; 15. } 16. 17./*** Private constructors are used to avoid the external use of new to instantiate object 19. */20.Privatesingletonf () {21st. } 22. 23./**The Readresolve method should be serialized when the Singleton object is 25. */26.PrivateObject readresolve () {27.returngetinstance (); 28. } 29.}
Example of an Android source code singleton model
1. Calendar Module
App Path: Packages/providers/calendarprovider
Files: Packages/providers/calendarprovider/src/com/android/provider/calendar/calendardatabasehelper.java
Single-Case Code:
Private Static NULL ; Public Static synchronized Calendardatabasehelper getinstance (context context) { ifnull) { New calendardatabasehelper (context); } return Ssingleton; }
As can be seen, this is used in the 2 singleton pattern B.
2.Collator class
Files: Libcore/luni/src/main/java/com/ibm/icu4jni/text/callator.java
Libcore/luni/src/main/java/com/ibm/icu4jni/text/rulebasedcallator.java
Single-Case Code:
Collator publicstatic getinstance (locale locale) { . return New rulebasedcollator (locale); .} RuleBasedCollator (locale locale) { . M_collator_ = Nativecollation.opencollator (locale.tostring ()); . Static native int opencollator (String locale);
This is the single pattern E, which is given above, a singleton mode with parameters
3.Editable class
Files: Frameworks/base/core/java/android/text/editable.java
Private Static New editable.factory (); /** * Returns the standard Editable Factory. */ Public Static editable.factory getinstance () { return sinstance; }
This is a singleton mode D is an example of an application
4.AccessibilityManager class
Files: Frameworks/base/core/java/android/view/accessibility/accessibilitymanager.java
Public Static Accessibilitymanager getinstance (context context) { synchronized (sinstancesync) { ifnull) { new Accessibilitymanager (context); } } return sinstance; }
This is the application of the singleton mode C.
There are many places where Android uses singleton mode, especially when the database is created, and it is used in singleton mode. Because each singleton mode trial scenario is not the same, Android uses different singleton mode implementations in different places.