In the book "Java and Patterns" of Dr. Shanhong, this describes the singleton pattern:
As an object's creation mode, Singleton mode ensures that a class has only one instance, and instantiates itself and provides this instance to the system as a whole. This class is called a singleton class.
Structure of the Singleton pattern
the characteristics of the singleton mode:
- A singleton class can have only one instance.
- The Singleton class must create its own unique instance.
- The Singleton class must provide this instance to all other objects.
a hungry man single-case class
Public class Eagersingleton {
Private Static New Eagersingleton ();
/**
* Private Default construction child
*/
Private Eagersingleton () {}
/**
* Static Factory method
*/
Public Static Eagersingleton getinstance () {
return instance;
}
}
In the above example, when the class is loaded, the static variable instance is initialized, and the private constructor of the class is called. In this case, the only instance of the Singleton class is created.
A hungry man type is actually a kind of comparative image appellation. Now that you are hungry, when you create an object instance, you are more anxious and hungry, so you create an object instance when you load the class.
Private Static New Eagersingleton ();
a hungry man-type is a typical space change time , when the class is loaded will create an instance of the class, whether you do not use, first created, and then each time the call, there is no need to judge, save the running time.
Lazy Single-case class
Public classLazysingleton {
Private StaticLazysingleton instance =NULL;
/**
* Private Default construction child
*/
PrivateLazysingleton () {}
/**
* Static Factory method
*/
Public Static synchronizedLazysingleton getinstance () {
if(Instance = =NULL){
Instance =NewLazysingleton ();
}
returnInstance
}
}
In the above lazy singleton class implementation, the static factory method is synchronized to handle multi-threaded environments.
The lazy type is actually a kind of comparative image appellation. Now that you're lazy, you don't have to worry about creating an object instance. Will wait until the immediate use of the object instance will be created, lazy people, always can not shirk the time to actually do the work, so when loading the object does not create an object instance.
Private Static null;
Lazy-type is a typical time to change space , that is, every time you get an instance will be judged to see if you need to create an instance, wasting judgment time. Of course, if no one ever uses it, it doesn't create an instance, saving memory space
Because the lazy implementation is thread-safe, this reduces the speed of the entire visit and is judged every time. So is there a better way to achieve it?
double check plus lock
This can be achieved by using double-check lock, which enables both thread safety and performance to be unaffected. So what is the "double check plus lock" mechanism?
The so-called "double check plus lock" mechanism, refers to: not every time into the GetInstance method need to synchronize, but first out of sync, enter the method, first check whether the existence of the instance, if not exist before the following synchronization block, this is the first check, into the synchronization block, again check if the instance exists, If it does not exist, an instance is created in the case of synchronization, which is the second check. In this way, you only need to synchronize once, which reduces the time wasted in the synchronization of multiple judgments.
The implementation of the "double check lock" mechanism uses the keyword volatile, which means that the value of thevariable modified by the volatile will not be cached by the local thread, and all reads and writes to that variable are directly operating shared memory. This ensures that multiple threads can handle the variable correctly.
Note: In java1.4 and previous versions, many JVM issues with the implementation of the volatile keyword will result in a "double check lock" failure, so the "double check lock" mechanism can only be used in versions Java5 and above.
Public classSingleton {
Private volatile StaticSingleton instance =NULL;
PrivateSingleton () {}
Public StaticSingleton getinstance () {
//Check that the instance exists before entering the following synchronization block if it does not exist
if(Instance = =NULL){
//synchronization blocks, thread-safe creation instances
synchronized(Singleton.class) {
//Check again if the instance exists, and if it does not exist, actually create the instance
if(Instance = =NULL){
Instance =NewSingleton ();
}
}
}
returnInstance
}
}
This approach enables thread-safe creation of instances without much impact on performance. It is just the first time to create an instance of synchronization, the future does not need synchronization, thereby speeding up the speed of operation.
tip : because the volatile keyword may block out some of the necessary code optimizations in a virtual machine, it is not very efficient to run. It is therefore generally recommended that no special needs be used. In other words, although you can use the double check and lock mechanism to implement a thread-safe singleton, it is not recommended to be used extensively, depending on the situation.
According to the above analysis, the two common single-instance implementations have a small flaw, then there is a scheme, both to achieve lazy loading, but also to achieve thread safety?
Lazy Initialization Holder class mode
This pattern synthesizes the knowledge of Java class-level internal classes and multithreading default synchronization locks, and cleverly implements both lazy loading and thread safety.
1. The corresponding basic knowledge
- What is a class-level inner class?
Simply put, the class-level inner class refers to a member-style inner class that has static adornments. If there is no static adornment, the member inner class is called an object-level inner class.
The class-level inner class is equivalent to the static component of its outer class, which has no dependencies on the object and the outer class object, so it can be created directly. An instance of an object-level inner class is bound to an instance of an external object.
In a class-level inner class, you can define a static method. Only static member methods or member variables in an external class can be referenced in a static method.
Class-level internal classes are equivalent to members of their external classes and are loaded only when they are first used.
- Knowledge of multithreading default Sync lock
As we all know, in multithreaded development, in order to solve the concurrency problem, mainly by using synchronized to add mutual exclusion lock for synchronous control. In some cases, however, the JVM has implicitly synchronized for you, in which case you do not have to synchronize control yourself. These situations include:
1. When initializing data by a static initializer (on a static field or an initializer in a static{} block)
2. When you access the final field
3. When creating an object before creating a thread
4. When the thread can see the object it will be working on
2. Solution Ideas
To implement thread safety very simply, you can use a static initializer, which can be used by the JVM to ensure thread security. such as the previous a Hungry man-style implementation. But isn't that going to waste a certain amount of space? Because of this implementation, the object is initialized when the class is loaded, whether you need it or not.
If there is now a way to allow the class to be loaded without initializing the object, does that solve the problem? One possible way is to use class-level inner classes to create object instances within this class-level inner class. This way, as long as the class-level inner class is not used, the object instance is not created, allowing for both lazy loading and thread safety.
The sample code is as follows:
Public classSingleton {
PrivateSingleton () {}
/**
* Class-Level inner class, which is a static member-inner class, an instance of the inner class and an instance of the outer class
* There is no binding relationship, and it is loaded only when it is called, allowing for lazy loading.
*/
Private Static classsingletonholder{
/**
* Static initializers, which are guaranteed by the JVM for thread safety
*/
Private StaticSingleton instance =NewSingleton ();
}
Public StaticSingleton getinstance () {
returnSingletonholder.instance;
}
}
When the GetInstance method is called for the first time, It first reads singletonholder.instance, causing the Singletonholder class to be initialized, and when the class is loaded and initialized, it initializes its static domain to create an instance of singleton, because it is a static domain, so only when the virtual machine loads the class Initialized once and is guaranteed to be thread-safe by a virtual machine.
The advantage of this pattern is that the GetInstance method is not synchronized and only performs a domain access, so deferred initialization does not add any access costs.
Singleton and enumeration
As described in "Efficient Java Second Edition", the single-element enumeration type has become the best way to implement Singleton. It is very simple to use enumerations to implement a singleton, just to write an enumeration type that contains a single element.
Public enum Singleton {
/**
* Defines an enumerated element, which represents an instance of singleton.
*/
Uniqueinstance;
/**
* Single instance can have its own operation
*/
Public void singletonoperation () {
// function Handling
}
}
Using enumerations to implement single-instance control is more concise, provides a free serialization mechanism, and provides a fundamental safeguard from the JVM, which absolutely prevents multiple instantiations, and is a more concise, efficient, and secure way to implement a single case.
End
A single-instance pattern of Java design patterns