definition
Application scenarios
Singleton implementation
Hungry Chinese
lazy
double check lock
enum class
static inner class
Singleton pattern extension
thread unique singleton
The only instance of the cluster
multi-instance mode
definition
A singleton is a class that has the following characteristics:
Only one object is allowed to be created
Provides a global access point
This object must have a class created by itself
Application scenarios
- Represents globally unique classes: serial number generators, classes that hold some fixed information (e.g. configuration files, keys)
- Handling conflicting access to resources: classes that write to files
Singleton implementation
Hungry Chinese
Hungry style is to create a Singleton object when the class is loaded, that is, it is not created when it needs to be used (lazy loading is not supported) is its biggest problem, and it is easy to waste resources (the possibility is a little small).
public class Singleton {
// 保存该类的唯一实例
private static Singleton instance = new Singleton();
/* **
私有构造器使其他类无法直接通过new创建该类的实例*
/
private Singleton() {
// 什么也不做
}
/* **
获取单例的主要方法*
/
public static Singleton getInstance() {
return instance;
}
}
lazy
The following is the simplest implementation of a hungry Chinese-style singleton. It is only loaded when needed, but there will be problems with this way of writing. For example, thread A calls getInstance to find instance == null
and then it executes At position 2 (assuming that the object has not been successfully new at this time), at this time, another thread B enters and finds that the instance is still null at this time and will also create a new object, which results in that the objects obtained by thread A and thread B are not the same object, this is the problem that the following code will have in multi-threaded conditions.
public class Singleton {
// 保存该类的唯一实例
private static Singleton instance = null;
/* **
私有构造器使其他类无法直接通过new创建该类的实例*
/
private Singleton() {
// 什么也不做
}
/* **
获取单例的主要方法*
/
public static Singleton getInstance() {
if(instance == null){ //1
instance = new Singleton();//2
}
return instance;
}
}
The above problem seems to be solved well → lock
Locking does solve the above problems, but in the future, each getInstance will have another lock process, which is not perfect! So there is the following implementation of double check lock.
public class Singleton {
// 保存该类的唯一实例
private static Singleton instance = null;
/* **
私有构造器使其他类无法直接通过new创建该类的实例*
/
private Singleton() {
// 什么也不做
}
/* **
获取单例的主要方法*
/
public static synchronized Singleton getInstance() {
if(instance == null){ //1
instance = new Singleton();//2
}
return instance;
}
}
double check lock
The following is a singleton implementation of a classic double check lock
public class Singleton {
// 保存该类的唯一实例
private static Singleton instance = null;
/* **
私有构造器使其他类无法直接通过new创建该类的实例*
/
private Singleton() {
// 什么也不做
}
/* **
获取单例的主要方法*
/
public static Singleton getInstance() {
if (null == instance) {// 操作1:第1次检查
synchronized (Singleton.class) { //操作2
if (null == instance) {// 操作3:第2次检查
instance = new Singleton(); // 操作4
}
}
}
return instance;
}
}
First, let's analyze why operation 1 and operation 2 work
Due to the above problems, adding an operation 2 before operation 3 will ensure that only one thread will execute operation 4 at a time. However, this will cause the lock to be applied/released every time getInstance() is called, which will cause extreme Large performance consumption, so you need to add an operation 1 before operation 2 to avoid such problems.
In addition, the static modification variable ensures that it will only be loaded once.
So it seems that this double verification lock is perfect?
The above operation 4 can be divided into the following 3 sub-operations
objRef = allocate(IncorrectDCLSingletion.class); // 子操作1:分配对象所需的存储空间
invokeConstructor(objRef); // 子操作2:初始化objRef引用的对象
instance = objRef; // 子操作3:将对象引用写入共享变量
Reordering is allowed in the synchronized critical area. The JIT compiler may reorder the above operations into sub-operation 1 → sub-operation 3 → sub-operation 2, so what may happen is that a thread executes the reordered operation 4 When (1→3→2), when the thread has just executed sub-operation 3 (sub-operation 2 has not been executed), there are other threads executing operation 1, then instance ≠ null will directly return it. , but this instance is not initialized, so there will be problems.
If the instance is decorated with the volatile keyword, this situation will not happen, volatile solves the reordering problem of sub-operation 2 and sub-operation 3.
Volatile also prevents this shared variable from not being stored in a register, avoiding visibility issues.
enum class
Enum classes can also safely implement the singleton pattern
public class EnumSingleton {
private EnumSingleton(){}
public enum InstanceObject{
INSTANCE;
public EnumSingleton getInstance(){
return new EnumSingleton();
}
}
public static EnumSingleton getInstance(){
return InstanceObject.INSTANCE.getInstance();
}
}
static inner class
Since the static variable is initialized only when it is used, the Singleton instance will only be created when executing 1. In addition, the loading of the static inner class is loaded when the static inner class is called in the program, and the outer class is loaded when the static inner class is called in the program. Loading is not necessarily related.
public class Singleton {
/* **
私有构造器使其他类无法直接通过new创建该类的实例*
/
private Singleton() {
// 什么也不做
}
private static class SingletonHolder{
private static Singleton instance = new Singleton();
}
/* **
获取单例的主要方法*
/
public static synchronized Singleton getInstance() {
return SingletonHolder.instance; //1
}
}
The above is the implementation of the inner static class, InstanceHolder will be loaded when it is called, so this is also a lazy singleton.
Singleton pattern extension
thread unique singleton
This kind of singleton is that each thread can only create a unique object, and a kv container can be created to store the relationship between the object and the thread. The following code is to implement a hungry Chinese thread unique singleton.
public class ThreadSingleton {
//类变量
private static Map<Thread,ThreadSingleton> threadSingletonMap = new HashMap<>();
private ThreadSingleton() {
}
public static ThreadSingleton getInstance() {
if (!threadSingletonMap.containsKey(Thread.currentThread())){
threadSingletonMap.put(Thread.currentThread(),new ThreadSingleton());
}
return threadSingletonMap.get(Thread.currentThread());
}
}
In addition to the above method, it is easier to use ThreadLocal to implement
public class ThreadLocalSingleton {
private static ThreadLocal<ThreadLocalSingleton> threadLocal = new ThreadLocal<>(){
@Override
protected Object initialValue() {
return new ThreadLocalSingleton();
}
};
private ThreadLocalSingleton(){}
public static ThreadLocalSingleton getInstance(){
return threadLocal.get();
}
}
The only instance of the cluster
Generally, a singleton refers to a singleton for the same virtual machine, and the only singleton in a cluster may involve multiple virtual machines, so it needs to be implemented with the help of persistence technology, such as serializing objects and storing them in a database or In the file, it is then converted into an object by deserialization. In addition, in order to ensure that only one service owns the object at any time, a lock (distributed lock) is required.
multi-instance mode
The multi-instance mode is that a class has only so few fixed objects, that is, the objects obtained in other classes must be one of them.
public class MultiSingleton {
private static Map<Integer,MultiSingleton> multiSingletonMap = new HashMap<>();
static {
multiSingletonMap.put(0,new MultiSingleton());
multiSingletonMap.put(1,new MultiSingleton());
multiSingletonMap.put(2,new MultiSingleton());
}
private MultiSingleton(){
}
public static MultiSingleton getInstance() {
return multiSingletonMap.get(new Random().nextInt(3));
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。