单例模式的概念
一个类在一定的作用域范围内只允许创建一个对象(或实例),那这个类就是一个单例类,这个设计模式就叫单例模式(Singleton Design Pattern)。根据作用域范围的不同,单例模式的实现思路可能会有不同。
单例模式的使用原因
优雅地处理资源访问冲突
比如一个程序里只有一个日志文件,如果这个日志文件对象在该进程内不是单例的,那么当程序里还有其他线程也要获取这个对象并有写入操作,就得进行互斥访问,编码就会变得较为复杂。
业务逻辑上该类就是只允许创建一个对象
经常业务逻辑上有的类就只允许创建一个对象。
如何设计单例
单例模式的设计思路很多,实现一个单例模式无非要考虑以下几点要求:
- 隐藏构造方法,不可随意创建对象;
- 考虑多线程下单例对象的获取是否存在安全问题,以免破坏单例约束;
- 可能有时候该类的占用资源较大,所有要考虑是否可以延迟加载;
- 获取单例对象的性能好不好;
以下是常见的集中单例设计方式:
饿汉式
public class DemoSingleton {
private static final DemoSingleton instance = new DemoSingleton();
// 隐藏构造方法
private DemoSingleton() {};
// 提供获取单例对象的方法
public static DemoSingleton getInstance() {
return instance;
}
// 业务逻辑
}
饿汉式的优点:
- 单例对象在类加载时就已经创建并初始化,避免了多线程下单例对象创建时的安全问题;
- 实现方式简单
饿汉式的缺点:
- 因为单例对象在类加载时完成创建和初始化,没有延迟加载的效果;
懒汉式
public class DemoSingleton {
private static final DemoSingleton instance;
// 隐藏构造方法
private DemoSingleton() {}
// 提供获取单例对象的方法
// 通过使获取单例对象的并发度为1,从而保证多线程下单例对象的获取是安全的
public static synchronized DemoSingleton getInstance() {
if (null == instance) {
instance = new DemoSingelton();
}
return instance;
}
// 业务逻辑
}
懒汉式的优点:
- 可以实现单例对象延迟加载;
- 实现上简单粗暴,符合单例模式的直观思维;
懒汉式的缺点:
- 获取单例对象的并发度过低,高并发下性能差;
懒汉式优化—双重检测
public DemoSingleton {
private static volatile DemoSingleton instance;
// 隐藏构造方法
private DemoSingleton() {};
// 提供公开的获取单例对象的方法
public static DemoSingleton getInstance() {
if (null == instance) {
synchronized(DemoSingleton.class) { // 进程级别的锁,如果换成分布式锁就能实现分布式下的单例
if (null == instance) {
instance = new DemoSingleton();
}
}
}
return instance;
}
// 业务逻辑
}
双重检测的优点:
- 相比懒汉式提高了性能,也具备延迟加载特性
- 设计模型比较完备,容易类比(比如说很容易类比出分布式下的单例模式设计方法)
双重检测的缺点:
- 实现逻辑上比较繁琐,技术细节会比较多
静态内部类
public class DemoSingleton {
// 隐藏构造方法
private DemoSingleton() {}
// 静态内部类
private static class SingletonHolder {
private static final DemoSingleton instance = new DemoSingleton();
}
// 对外获取单例对象的方法
public static DemoSingleton getInstance() {
return SingletonHolder.instance;
}
// 业务逻辑
}
优点:
- 简单高效,又达到了延迟加载的目的
缺点:
- 依赖了java的语言特性
枚举
public enum DemoSingleton {
INSTANCE;
// 业务逻辑
}
优点:
- 代码实现上非常简洁;
- 最为安全(语言特性上保证了序列化和反序列化都不会破坏单例性)
缺点:
- 依赖java的语言特性
参考
【1】极客时间—设计模式之美
【2】 《java设计模式》