文章目录
单例模式
单例对象(Singleton)是一种常用的设计模式。
1. 什么是单例模式
- 无论在反射、序列化、多线程、分布式等场景下都绝对只有一个实例,并且提供一个全局访问点
- 单例模式会隐藏所有的构造方法
- 属于创建型模式(其实没啥意思,要和建造者模式区分开)
单例模式能够保证一个类仅有唯一的实例,并提供一个全局访问点。
我们是不是可以通过一个全局变量来实现单例模式的要求呢?我们只要仔细地想想看,全局变量确实可以提供一个全局访问点,但是它不能防止别人实例化多个对象。通过外部程序来控制的对象的产生的个数,势必会系统的增加管理成本,增大模块之间的耦合度。所以,最好的解决办法就是让类自己负责保存它的唯一实例,并且让这个类保证不会产生第二个实例,同时提供一个让外部对象访问该实例的方法。自己的事情自己办,而不是由别人代办,这非常符合面向对象的封装原则。
所以单例具备下面三个特点
1、单例类确保自己只有一个实例。
2、单例类必须自己创建自己的实例。
3、单例类必须为其他对象提供唯一的实例。
2. 优点有哪些?为啥使用?
三点:创建和使用简单、减少GC、安全
1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
3、有些类如交易所的核心交易引擎,控制着交易流程,
如果该类可以创建多个的话,系统完全乱了。
(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),
3. 经典的应用
Spring中的单例: ServletContext 、 ServletConfig 、 ApplicationContext 、 DBPool
4. 单例的分类
· 懒汉式单例类
对于懒汉模式,我们可以这样理解:该单例类非常懒, 只有在自身需要的时候才会行动,从来不知道及早做好准备。 它在需要对象的时候,才判断是否已有对象,如果没有就立即创建一个对象, 然后返回,如果已有对象就不再创建,立即返回 懒汉模式只在外部对象第一次请求实例的时候才去创建。
· 饿汉式单例 对于饿汉模式,我们可以这样理解:该单例类非常饿, 迫切需要吃东西,所以它在类加载的时候就立即创建对象。
懒汉、饿汉模式的优缺点:
懒汉模式,它的特点是运行时获得对象的速度比较慢,但加载类的时候比较快。
它在整个应用的生命周期只有一部分时间在占用资源。
饿汉模式,它的特点是加载类的时候比较慢,但运行时获得对象的速度比较快。
它从加载到应用结束会一直占用资源。
这两种模式对于初始化较快,占用资源少的轻量级对象来说,没有多大的性能差异,选择懒汉式还是饿汉式都没有问题。
但是对于初始化慢,占用资源多的重量级对象来说,就会有比较明显的差别了。
所以,对重量级对象应用饿汉模式,类加载时速度慢,但运行时速度快;
懒汉模式则与之相反,类加载时速度快,但运行时第一次获得对象的速度慢。
从用户体验的角度来说,我们应该首选饿汉模式。
我们愿意等待某个程序花较长的时间初始化,却不喜欢在程序运行时等待太久,给人一种反应迟钝的感觉,
所以对于有重量级对象参与的单例模式,我们推荐使用饿汉模式。
而对于初始化较快的轻量级对象来说,选用哪种方法都可以。
如果一个应用中使用了大量单例模式,我们就应该权衡两种方法了。轻量级对象的单例采用懒汉模式,减轻加载时的负担,缩短加载时间,提高加载效率;同时由于是轻量级对象,把这些对象的创建放在使用时进行,实际就是把创建单例对象所消耗的时间分摊到整个应用中去了,对于整个应用的运行效率没有太大影响。
下面我们将用代码的方式介绍单例模式:
各种单例模式
源码地址:github地址
饿汉单例模式
饿汉单例模式 | 详细介绍 | 带来的问题 | 如何解决 |
---|---|---|---|
SimpleHungrySingleton | 最简单单例模式 | ||
StaticHungrySingleton | 和SimpleHungrySingleton一样 | ||
StaticPropertyHungry | 带有全局属性的单例模式 | 获取属性的时候会进行类的初始化 | 静态内部类实现 |
懒汉单例模式
懒汉单例模式 | 带来的问题 |
---|---|
SimpleLazySingleton | 线程不安全 |
SyncLazySingleton | 效率缓慢 |
DoubleCheckLazySingleton(DDL) | 线程不安全(内存重排序) |
DoubleCheckVolatileLazySingleton(DDL+volatile) | 完美但是很复杂 |
静态内部类实现单例模式
静态内部类单例模式 | 带来的问题 |
---|---|
InnerClassSingleton | 反射破坏单例 |
InnerClassSingleton2 | 反射安全但是抛出异常了 |
枚举和SpringIOC
注册式单例模式 | 带来的问题 |
---|---|
EnumSingleton | |
IocContainerSingleton |
ThreadLocal实现单例模式
ThreadLocal单例模式 | 问题 |
---|---|
ThreadLocal | 每个线程是单例,不同线程不是 |
源码地址:github地址