目录
定义
解决了什么问题(应用场景)
如何实现
饿汉式
懒汉式
双重检测
静态内部类
枚举
单例模式存在什么问题
是否有其它替代方案
参考资料
定义
一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。
解决了什么问题(应用场景)
- 从业务概念上,有些数据在系统中只应该保存一份,就比较适合设计为单例类。比如,系统的配置信息类。
- 我们还可以使用单例解决资源访问冲突的问题。
如何实现
要实现一个单例,我们需要关注的点无外乎下面几个:
- 构造函数需要是 private 访问权限的,这样才能避免外部通过 new 创建实例;
- 考虑对象创建时的线程安全问题;
- 考虑是否支持延迟加载;
- 考虑 getInstance() 性能是否高(是否加锁)。
饿汉式
在类加载的时候,instance 静态实例就已经创建并初始化好了。类加载是线程安全的 instance 自然也就是线程安全的。不过,这种实现方式不支持延迟加载。
public class IdGenerator { private AtomicLong id = new AtomicLong( 0 ); private static final IdGenerator instance = new IdGenerator(); private IdGenerator() {} public static IdGenerator getInstance() { return instance; } public long getId() { return id.incrementAndGet(); } } |
懒汉式
支持延迟加载,不过并发度低
public class IdGenerator { private AtomicLong id = new AtomicLong( 0 ); private static IdGenerator instance; private IdGenerator() {} public static synchronized IdGenerator getInstance() { // 加了一把粒度很大的锁,导致并发度低 if (instance == null ) { instance = new IdGenerator(); } return instance; } public long getId() { return id.incrementAndGet(); } } |
双重检测
支持延迟加载,并发度高
public class IdGenerator { private AtomicLong id = new AtomicLong( 0 ); private static IdGenerator instance; private IdGenerator() {} public static IdGenerator getInstance() { if (instance == null ) { synchronized (IdGenerator. class ) { // 此处为类级别的锁 if (instance == null ) { instance = new IdGenerator(); } } } return instance; } public long getId() { return id.incrementAndGet(); } } |
静态内部类
实现简单,支持延迟加载
public class IdGenerator { private AtomicLong id = new AtomicLong( 0 ); private IdGenerator() {} private static class SingletonHolder{ private static final IdGenerator instance = new IdGenerator(); // 是线程安全的 } public static IdGenerator getInstance() { return SingletonHolder.instance; } public long getId() { return id.incrementAndGet(); } } |
枚举
枚举个锤子
最简单的实现方式,基于枚举类型的单例实现。这种实现方式通过 Java 枚举类型本身的特性,保证了实例创建的线程安全性和实例的唯一性。
public enum IdGenerator { INSTANCE; private AtomicLong id = new AtomicLong( 0 ); public long getId() { return id.incrementAndGet(); } } |
单例模式存在什么问题
42讲,没看懂
是否有其它替代方案
使用工厂模式,使用依赖注入
参考资料
极客时间--设计模式之美--第41讲,42讲,43讲