A single-instance pattern of Java design Patterns
In design mode, the simplest one is the singleton pattern. First look at the singleton Mode singleton mode can be very simple, it all only need a class to complete. However, if the "number of objects created and when to be created" on the two points, Singleton mode can be quite complex, more complex than the first five modes combined, such as the DCL Double lock detection (double checked locking) discussion, Involves multiple ClassLoader (ClassLoader), when it comes to 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.
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:
public class singletona { /** * Singleton object instance */ private Span class= "Hljs-keyword" >static Singletona instance = null ; public static Singletona getinstance () {if (instance = =
null ) {
//line Instance =
new Singletona ();
//line }
return instance; } }
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:
public class singletonb { /** * Singleton object instance */ private Span class= "Hljs-keyword" >static singletonb instance = null ; public synchronized static Singletonb getinstance () {if (instance = =
null ) {instance =
new singletonb (); }
return instance; } }
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.
Implement 3 single-case mode C:
Public class singletonc { /** * Singleton object instance * / Private StaticSingletonkerrigand instance =NULL; Public StaticSingletoncgetinstance() {if(Instance = =NULL) {synchronized(Singletonc.class) {if(Instance = =NULL) {instance =NewSingletonc (); } } }returnInstance } }
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:
publicclass SingletonD { /** * 单例对象实例 */ privatestaticnew SingletonD(); publicstaticgetInstance() { return instance; } }
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:
Mode e with Parameters
public class singletone { private static class singletonholder {
/** * Singleton object instance */
static
final singletone INSTANCE =
new singletone (); }
public
static singletone
getinstance () {
return singletonholder.instance; } }
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:
Public class singletonf implements Serializable { Private Static class singletonholder { /** * Singleton object instance * / Static Finalsingletonf INSTANCE =NewSingletonf (); } Public StaticSingletonfgetinstance() {returnSingletonholder.instance; }/** * Private constructor is used to avoid external instantiation of objects directly using new */ Private singletonf() { }The /** * Readresolve method should be used when a singleton object is serialized */ PrivateObjectReadresolve() {returnGetInstance (); } }
A single-instance pattern of Java design Patterns