定义
一个类只允许创建一个实例
使用场景
- 只应该存在一份的数据,例如配置信息
- 控制共享资源的并发访问
实现方式
饿汉式
在类加载时就创建好对象
优点:
如果创建逻辑有问题或者资源不足等原因导致创建失败,能在启动时就发现问题,早发现早解决
缺点:
不支持延迟加载,启动时间变长,可能会创建了实际上用不到的实例,浪费资源
懒汉式
需要用到时才创建
优点:
延迟加载,避免浪费资源;启动时间变短
缺点:
需要通过加锁来实现线程安全,并发能力低下;如果初始化时间长,可能导致服务响应时间长,影响业务体验;
双重检测
需要用到时,判断是否已创建。已创建则直接返回实例;未创建则进入加锁的创建逻辑,然后在创建完后再返回实例
优点:
相对饿汉式而言,支持了延迟加载;相对懒汉式而言,提升了并发能力
缺点:
相对而言没有明显缺点
静态内部类
使用java静态内部类的机制,即实现了延迟加载,也具备高并发支持能力,同时代码相对简单
public class MyObject {
private static class SingltonHolder{
private static final Singlton instance = new Singlton();
}
public static MyObject getInstance(){
return SingltonHolder.instance;
}
}
枚举
利用枚举类的特性,实现了单例和线程安全
public enum LongSerquence{
INSTANCE
;
private AtomicLong atomicLong = new AtomicLong(0);
private getNext(){
return atomicLong.incrementAndGet();
}
}
优点:
最简洁的代码实现了单例,且没有线程安全问题,并发支持能力强
缺点:
与枚举的常用场景不同,虽然能实现所需的功能,但不是通俗的使用方式。有“歪打误撞”之嫌,个人认为优势不明显的情况下,还是使用其他方式更佳
单例模式存在的问题
- 构造函数只能是无参的
- 对“面向抽象编程”不友好,通常写出来的代码都是硬编码,基于具体的实现而不是抽象
- 扩展性不好 当需要新增一种实现时,需要进行较大改动