单例模式
单例模式 - 大话设计模式
*每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。*
单例模式(Singleton)
保证一个类仅有一个实例, 并提供一个访问的全局访问点[^ DP]
为了不实例化出多个对象,让类自身负责保存他的唯一实例. 这个类可以保证没有其他实例可以被创建, 并且他可以提供一个访问该实例的方法
单例模式
单例模式因为Singleton类封装了他唯一的实现类, 可以严格控制客户怎样访问以及何时访问它.—对唯一实例的受控访问
示例代码:
java
1
2
3
4
5
6
7
8
9
10
11 public class Singleton {
private static Singleton instance; // private的实例变量
private Singleton() {
System.out.println("you win!!!");
} // 私有的构造方法 让其他类不能访问
public static Singleton getInstance() {
if (instance == null) instance = new Singleton(); // 如果实例为空则创建
return instance;
}
多线程单例模式
在多个线程中, 单例模式会出现多个线程同时访问Singleton类, 会出现创建了多个实例的情况. 所以我们给他加锁
双重锁定
当然加锁后每个线程想访问Singleton类都要等待了, 所以我们优化一下 — 双重锁定
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 public class Singleton {
private static Singleton intance; // private的实例变量
private static Object synchronizedLOCK = new Object(); // 锁对象
//只有static的成员才能在没有创建对象时进行初始化。且类的静态成员在类第一次被使用时初始化后就不会再被初始化,保证了单例
private Singleton() {
System.out.println("you win!!!");
} // 私有的构造方法 让其他类不能访问
public static Singleton getIntance() {
if (intance == null) {
synchronized (synchronizedLOCK) {
if (intance == null) {
intance = new Singleton();
} // 如果实例为空则创建
}
}
return intance;
}
饿汉/懒汉单例类
饿汉
- 静态初始化的方式在自己被加载时就将自己实例化
java
1
2
3
4
5
6
7
8
9
10
11 public class SingletonHungry {
private static SingletonHungry intance = new SingletonHungry();
public SingletonHungry() {
System.out.println("Creat new !!!");
}
public static SingletonHungry getIntance() {
return intance;
}
}懒汉
- 在第一次被引用时,才会将自己实例化
优缺点: 饿汉类一加载就实例出对象, 会提前占用系统资源. 懒汉面临多线程访问的单圈问题,要加双重锁定. 具体用哪个取决于实际需求
具体用哪个取决于实际需求
懒汉下防止指令重排序
创建实例的方式intance = new Singleton(); 这不是一个原子性的操作
执行实例化时有三步的
- 分配内存空间
- 执行构造方法,初始化对象
- 将对象指向分配的空间
如果指令2和3重排 那么创建的就是空对象…
java
1 | private volatile static Singleton intance; // 加入volatile防止重排 |
防止反射破坏单例模式
使用 一个加密的 开关参数(可以破译)
使用枚举 反射源码不允许创建枚举的实例 枚举是一个继承了Enum的类
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 大橘のBlog!
评论