设计模式之——单例模式
2017-05-16 本文已影响1人
齐舞647
单例模式:Singleton Pattern
原话:Ensure a class has only one instance ,and provide a global point of access to it.
直译:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
1. 定义:一个类只能产生一个对象。(我是皇帝我独苗)
2. 方法:把该类的构造函数设置为private(私有访问),外部无法访问该构造函数 且又没有办法调用系统默认构造函数,就可以禁止外部创建对象。
3. 示例类图:
单例模式通用类图4. 示例代码:
class Singleton{
private static final Singleton singleton = new Singleton();
//限制产生多个对象
private Singleton(){
//构造函数
}
//通过该方法获得实例对象
public static Singleton getSingleton(){
return singleton;
}
//其他方法,尽量是static
public static void doSomeThing(){
//...
}
}
5. 优点:
1.只有一个实例,减少了内存开支
2.减少了系统的性能开销
3.避免了对同一个资源文件的同时写操作
4.可以在系统内设置全局访问点,优化和共享资源访问,负责所有数据表的映射处理
6. 缺点:
1.没有借口,扩展很困难
2.对测试不利,单例模式没有完成,不能进行测试
3.与单一职责有冲突,一个类应该只实现一个逻辑,而不关心它是否是单例的
7. 应用场景:
1.要一个类有且仅有一个对象
2.需要一个共享访问点或共享数据
3.创建一个对象需要的资源过多
4.需要定义大量的静态常量和方法
8. 注意事项:
在高并发的情况下,需要考虑单例模式的线程同步问题,
可能会出现两个对象,破坏了最初的预期
9. 双重检验加锁:强化单例加锁
//强化单例:
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
- 线程1进入方法体,满足条件instance == null,进入synchronized块
- 线程间抢占cpu资源,线程1被线程2预占,线程2进入方法体
- 此时方法还没执行完,对象还没有创建出来instance依然为null
- 线程2试图获取锁资源,但线程1持有该锁,于是线程2阻塞,线程2被线程1预占
- 线程1继续执行,此时instance 仍然为null,创建Singleton实例并将其引用赋值给instance,方法返回该实例对象的引用,退出方法
- 线程1被线程2预占,线程2获取锁并检查 instance是否为 null.由于instance 已经被赋值,所以不会创建第二个 Singleton 对象.
- 这样一套双重检查加锁机制实现了比普通单例模式更高效率的逻辑
其中,双重检索加锁:参考了某位简书博主