单例模式浅谈 ——饿汉式及懒汉式的Java实现

经常工作面试的时候,面试官会问,怎么保证某个类在程序运行过程中只有一个对象存在?

以上问题,实际就是面试官在了解面试者对单例模式的了解。

一.为什么需要单例模式

以常见的使用计算机打印文件为例,假设计算机拥有A,B两台连接的打印机,如后台打印程序也有两个的话,可能造成如下问题:

当打印文档的时候,因为打印程序也有多个,可能造成一份完整文档同时被两个打印程序同时进行分配,导致A,B打印机互相不知道在打印什么,导致混乱。

所以,每台计算机可以有若干个打印机,但只能有一个后台打印程序,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。

 在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。

总之,选择单例模式就是为了避免不一致状态,避免政出多头。

二.单例模式的特点

1. 单例模式只能有一个实例。

2. 单例类必须创建自己的唯一实例。

3. 单例类必须向其他对象提供这一实例。

三.单例模式的分类

1.饿汉式单例

2.懒汉式单例

3.登记式单例

登记式单例是为了解决模式1,2不能继承的问题而开发的,本身存在争议,暂不讨论。

四.单例模式的开发

1.线程安全的饿汉模式

1)既然在程序中只能创建一个对象,那也就是说在不能在其它类中任意创建对象,否则对象肯定就不止一个,这就要求被创建那个类的构造方法不能public,也就是必须private,这个就保证了外部不能乱创建对象。

2)外面创建不了对象,也就只能在内部创建对象了,因为我们讲究Java的封装特性,对象是private,所以我们要提供一个public方法供外界调用。

3)因为在外面不可能创建对象,想调用方法就必须将方法static,这样就可以通过:类名.方法名获取对象了,又因为静态方法里只能用静态成员,所以single必须static化。

4)至此,创建一个对象的任务完成了,一般情况下,我们另外在static加个final,

最终程序如下

饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变无需关注多线程问题、写法简单明了、能用则用。

但是它是加载类时创建实例、所以如果是一个工厂模式、缓存了很多实例、那么就得考虑效率问题,因为这个类一加载则把所有实例不管用不用一块创建。

2.线程安全的懒汉式单例

之所以叫做懒汉模式,主要是因为此种方法可以非常明显的lazy loading,简单说就是什么时候用,什么时候建。

然而并发其实是一种特殊情况,大多时候这个锁占用的额外资源都浪费了,这种方式写出来的结构效率很低。

3.双重校验锁法

解释一下在并发时,双重校验锁法会有怎样的情景:

STEP 1. 线程A访问getInstance()方法,因为单例还没有实例化,所以进入了锁定块。

STEP 2. 线程B访问getInstance()方法,因为单例还没有实例化,得以访问接下来代码块,而接下来代码块已经被线程1锁定。

STEP 3. 线程A进入下一判断,因为单例还没有实例化,所以进行单例实例化,成功实例化后退出代码块,解除锁定。

STEP 4. 线程B进入接下来代码块,锁定线程,进入下一判断,因为已经实例化,退出代码块,解除锁定。

STEP 5. 线程A初始化并获取到了单例实例并返回,线程B获取了在线程A中初始化的单例。

理论上双重校验锁法是线程安全的,并且,这种方法实现了lazyloading。

Volatile关键字的作用: 禁止进行指令的重排序

4.静态类内部加载

使用内部类的好处是,静态内部类不会在单例加载时就加载,而是在调用getInstance()方法时才进行加载,达到了类似懒汉模式的效果,而这种方法又是线程安全的。

5.非常优雅的枚举实现单例模式

Effective Java作者Josh Bloch 提倡的方式,简洁而完美。解决了以下三个问题:

(1)自由序列化。

(2)保证只有一个实例。

(3)线程安全。

如果我们想调用它的方法时,仅需要以下操作:

五.总结一下:

推荐使用饿汉式和枚举实现单例模式,饿汉式完全不用考虑线程安全,枚举则是简单优雅;懒汉式的问题则是当没有高并发的情况下,白白浪费资源,效率低下;而且,如果创建对象时初始化的工作较多的话,可能会将这部分时间转嫁给用户,不太友好。

更多资深讲师相关课程资料、学习笔记请入群后向管理员免费获取,更有专业知识答疑解惑。入群即送价值499元在线课程一份。

QQ群号:560819979

敲门砖(验证信息):姑苏行

猜你喜欢

转载自blog.csdn.net/qq_41717874/article/details/82772615