23种设计模式-单例模式
产生背景
某些情况,如:线程池,一个项目中总线程数量以及生命周期,可能需要统一控制;如果线程池自身可创建多个实例,那么就无法统一控制,此时,只要能控制线程池对象的数量为一个,那么就可以实现统一控制的目标;
注意:现实中真正使用纯的单例模式并不多;
如:spring bean ,通过配置来决定是否使用单例;线程池、连接池也并未使用单例(如果完全使用单例,就没办法根据业务配置多个线程池和多数据源连接池)
概念
整个项目或系统的生命周期内,只创建一个对象;
原理
- 本质:
- 更像是一个能创建类自身实例的工具类;
关闭构造器
防止外部类通过new 创建实例
类内部创建一个实例
逻辑由内部实现;
对外只提供一个获取实例的 静态 方法
对外提供使用接口;
使用场景
只能创建一个对象的场景
实现方式
- 懒汉模式
- 概念相关:
- 所谓懒,就是在需要时才创建,不需要就不创建;所谓的需要就是调用;
- 优点:
- 第一次调用时产生对象,不需要提前创建一个可能永不使用的对象;
- 缺点:
- 创建时存在锁竞争;使用时需要null检查;
public class SingleModel{
//关闭构造器,防止通过new 创建
private SingleModel(){}
public static SingleModel getInstance(){
//第一次判断,防止进入锁判断
if (null == INSTANCE){
//加锁
synchronized (INSTANCE){
//二次判断,防止并发操作:多个线程同时竞争锁,第一个执行结束释放锁后,第二个进程等待获取锁后,又重新创建一次对象;
if (null == INSTANCE){
INSTANCE = new SingleModel();
}
}
}
return INSTANCE;
}
}
- 饿汉模式
- 概念相关
- 所谓饿,就是在需要对象之前就已经创建,需要时直接返回已经创建的对象即可;
- 优点:
- 使用时,不需要每次都进行null检查,和锁竞争;减小性能消耗;
- 缺点:
- 提前创建对象,可能对象永远不会使用;
public class SingleModel{
//关闭构造器,防止通过new创建对象
private SingleModel(){}
//类加载时创建:通过类加载的线程安全特性创建实例
private static final SingleModel INSTANCE = new SingleModel();
//直接返回实例
public static SingleModel getInstance(){
return INSTANCE;
}
}
- 折中模式
- 优点:
- 集成了懒汉和饿汉的所有优点;对象延迟创建;线程安全,无需要检查和加锁;
- 原理:
- A:类在第一次使用时才会加载(import并不会加载)
- B:类加载本身是线程安全的
- C:内部类可以调用外部类的私有构造器
- D:通过内部类的延迟加载,实现实例的延迟创建;通过内部类加载的线程安全性,创建静态属性引用外部对象;
public class SingleModel{
//关闭构造器,防止通过new创建对象
private SingleModel(){}
//内部类:静态属性-引用外部对象
private static class SingleInstanceModel{
private static final SingleModel INSTANCE = new SingleModel();
}
//第一调用时,才开始加载内部类,又通过内部类(类加载的线程安全性)的加载,生成外部对象;
public static SingleModel getInstance(){
return SingleInstanceModel.INSTANCE;
}
实际场景
主要开源项目中,真正使用纯的单例模式的例子并不多。