1.定义
确保某个类只有一个实例,并且自行实例化并向整个系统提供这个实例。
2.介绍
单例模式属于创建类模式。
单例模式有以下特点:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
3.实现
3.4 饿汉式
1 | //单例类. |
- 优点:写法简单,线程安全。
- 缺点:没有懒加载的效果,如果没有使用过的话会造成内存浪费。
3.1 懒汉式(线程不安全)
1 | //单例类 |
- 优点:实现了懒加载的效果。
- 缺点:线程不安全。
3.1 懒汉式(线程安全)
1 | //单例类 |
- 优点:实现了懒加载的效果,线程安全。
- 缺点:使用synchronized会造成不必要的同步开销,而且大部分时候我们是用不到同步的。
3.3 双重检查锁定(DCL)
1 | public class Singleton { |
- 优点:懒加载,线程安全,效率较高
- 缺点:volatile影响一点性能,高并发下有一定的缺陷,某些情况下DCL会失效,虽然概率较小。
3.5 静态内部类
1 | public class Singleton { |
优点:懒加载,线程安全,推荐使用
3.6 枚举单例
1 | public enum Singleton { |
- 优点:线程安全,写法简单,能防止反序列化重新创建新的对象。
- 缺点:可读性不高,枚举会比静态常量多那么一丁点的内存。
3.7 使用容器实现单例模式
1 | //单例管理类 |
- 优点:方便管理。
- 缺点:写法稍复杂。
4.注意事项
使用反射能够破坏单例模式,所以应该慎用反射
1 | Constructor con = Singleton.class.getDeclaredConstructor(); |
可以通过当第二次调用构造函数时抛出异常来防止反射破坏单例,以懒汉式为例:
1 | public class Singleton { |
反序列化时也会破坏单例模式,可以通过重写readResolve方法避免,以饿汉式为例:
1 | public class Singleton implements Serializable { |
5.应用场景
- 频繁访问数据库或文件的对象。
- 工具类对象;
- 创建对象时耗时过多或耗费资源过多,但又经常用到的对象;
6.优点
- 内存中只存在一个对象,节省了系统资源。
- 避免对资源的多重占用,例如一个文件操作,由于只有一个实例存在内存中,避免对同一资源文件的同时操作。
7.缺点
- 获取对象时不能用new
- 单例对象如果持有Context,那么很容易引发内存泄露。
- 单例模式一般没有接口,扩展很困难,若要扩展,只能修改代码来实现。