设计模式之单例
singleton
思想
确保一个类只有一个实例,并提供该实例的全局访问点
使用一个私有构造函数、一个私有静态变量、一个公有的静态函数来实现。
这样只能通过这个公有的静态函数来返回唯一的私有静态变量。
实现方式
- 懒汉式-线程不安全
私有静态变量uniqueInstance在使用的时候,被实例化
1 | public class Singleton { |
这种实现方式在多线程的环境下会存在多个线程同时进入if语句,创建多个实例。
- 饿汉式-线程安全
在类加载时,直接赋值创建实例,这样保证不会重复创建实例。
1 | private static Singleton uniqueInstance = new Singleton(); |
- 懒汉式-同步机制
通过给静态函数加锁,一个线程创建时,其他线程只能等待,保证了线程安全。但是锁粒度比较大,开销大。
1 | public class Singleton { |
- 懒汉式-双重检测
将锁的粒度减小,只需要给实例化的部分加锁,
首先判断是否已经生成实例,如果没有生成实例的时候才给实例化部分加锁。如果是这样,在没有实例化的时候,两个线程进入了if语句,所以加了同步控制,但是只是先后的顺序去实例化,会产生多实例。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getUniqueInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
所以需要双重检测,同步的情况下,第一个线程实例化之后,第二个语句进入同步块时,判断if的条件就不成立,也就控制了单实例。1
2
3
4
5if (uniqueInstance == null) {
synchronized (Singleton.class) {
uniqueInstance = new Singleton();
}
}
volatile 关键字修饰uniqueInstance, 因为uniqueInstance = new Singleton();语句分三步执行:
(1) 开辟存储空间
(2) 初始化对象
(3) 让uniqueInstance实例指向空间。
JVM具有指令重排的特性,可能执行顺序会编程1-3-2,多线程的情况下可能产生没有初始化的实例。volatile可以禁止指令重排,在多线程下正常运行。
- 静态内部类
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
private static Singleton INSTANCE = new Singleton();
}
public static Singleton getUniqueInstance() {
return SingletonHolder.INSTANCE;
}
} - 枚举实现
实现简单,在序列化和反射攻击时,可以防止多实例。1
2
3public enum Singleton {
uniqueInstance;
}
- Post title:设计模式之单例
- Post author:郭旭升
- Create time:2023-02-01 19:12:13
- Post link:2023/02/01/设计模式之单例/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.
Comments