java 设计模式之单例模式 一篇就够了


单例模式


单例对象(Singleton)是一种常用的设计模式。

1. 什么是单例模式

  1. 无论在反射、序列化、多线程、分布式等场景下都绝对只有一个实例,并且提供一个全局访问点
  2. 单例模式会隐藏所有的构造方法
  3. 属于创建型模式(其实没啥意思,要和建造者模式区分开)

不理解建造者模式的可以参考这里

单例模式能够保证一个类仅有唯一的实例,并提供一个全局访问点。

我们是不是可以通过一个全局变量来实现单例模式的要求呢?我们只要仔细地想想看,全局变量确实可以提供一个全局访问点,但是它不能防止别人实例化多个对象。通过外部程序来控制的对象的产生的个数,势必会系统的增加管理成本,增大模块之间的耦合度。所以,最好的解决办法就是让类自己负责保存它的唯一实例,并且让这个类保证不会产生第二个实例,同时提供一个让外部对象访问该实例的方法。自己的事情自己办,而不是由别人代办,这非常符合面向对象的封装原则。

所以单例具备下面三个特点

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地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值