单例模式【Singleton Pattern】

一、引言

在《Java编程思想》的第六章,介绍访问权限控制关键字private时,引出了单例模式,但书中并没有详细的说明,只是一带而过。关于private访问控制符,书中这样描述:“关键字private的意思是,除了包含该成员的类之外,其他任何类都无法访问这个成员”。

二、代码

单例模式的原理就是基于上面那句话,具体的做法是:将类的构造函数设置为private,这样,除了类自己的方法,无论外部其他类,都无法生成该类的对象,这样就可以控制该类生成的对象。单件模式能够保证某一类型对象在系统中的唯一性,即某类在系统中只有一个实例。
单例模式通俗的例子,就是古代大臣每天朝拜皇帝(默认每个朝代的皇帝都只有一个,哈哈~其中的皇帝必须是单例的)。在这个场景中,有皇帝,有大臣,大臣是天天要上朝参见皇帝的,今天参拜的皇帝应该和昨天、前天的一样,也必须一样。
单例模式的代码如下(懒汉式):

皇帝的实体类:
这里写图片描述

大臣的实体类:
这里写图片描述
通过运行程序的结果可以看到,大臣天天见到的都是同一个皇帝,不会产生错乱情况。

三、优化(饿汉式)

单例模式很简单,就是在构造函数前面private,这个模式是简单,但是简单中透着风险,风险?什么风险?在一个B/S 项目中,每个HTTP Request 请求到J2EE的容器上后都创建了一个线程,每个线程都要创建同一个单例对象,怎么办?好,我们写一个通用的单例程序,然后分析一下:
这里写图片描述
我们来看上图中红色标注的那三句话,假如现在有两个线程A和线程B,线程A执行到this.singletonPattern =
new SingletonPattern(),正在申请内存分配,该步骤可能需要0.001微秒,就在这0.001微秒之内,线程B执
行到if(this.singletonPattern == null),你说这个时候这个判断条件是true还是false?是true,那然后呢?线程B也往下走,于是乎就在内存中就有两个SingletonPattern 的实例了,看看是不是出问题了?

如果你这个单例是去拿一个序列号或者创建一个信号资源的时候,会怎么样?业务逻辑混乱!数据一致性
校验失败!最重要的是你从代码上还看不出什么问题,这才是最要命的!因为这种情况基本上你是重现不
了的,那怎么修改?有很多种方案,下面就说一种,能简单的、彻底解决问题的办法:
这里写图片描述
可以在定义对象的时候,直接执行创建对象操作,并且在getInstance()方法上加上同步操作,这样就可以解决上面所说的问题,大功告成!

四、总结

总结一下,两种方案公用方法getInstance()方法都是静态的(static),实例和构造方法又都是私有的(private)。但是饿汉式每次调用的时候不用做创建,直接返回已经创建好的实例。这样虽然节省了时间,但是却占用了空间,实例本身为static的,会一直在内存中带着。懒汉式则是判断,在用的时候才加载,会影响程序的速度。最关键的是,在并发的情况下,懒汉式是不安全的。
如何选择:
(1)如果单件模式实例在系统中经常会被用到,饿汉式是一个不错的选择。
(2)反之如果单件模式在系统中会很少用到或者几乎不会用到,那么懒汉式是一个不错的选择。

猜你喜欢

转载自blog.csdn.net/zxd1435513775/article/details/80472191