调侃《Head First 设计模式》之单例模式
来源:互联网 发布:大数据mobi 编辑:程序博客网 时间:2024/05/01 06:25
对于一个类来说,平常我们可以随便new出无限多个对象(只要内存hold得住),但是像线程池、缓存、对话框、日志对象、设备驱动程序的对象只能有一个对象,如果制造多个实例就会出现问题。比如程序行为异常,资源使用过量等。
那如何让一个类只能有一个对象呢?也许你想到了在另一个类持有该类的对象引用,在要new出这个类的时候判断下该引用是否为空就可以了。但这样做会提高类间的耦合度,而且会在不同类间出现重复代码。明明是你自己只能有一个实例这件事,却还得别人帮你做,这显然不好,所以要让类自己去让自己只可以有一个实例。所以我们只能从它的构造器入手。我们按照如下步骤思考:
1.首先不能让其他的类随便调用它的构造器,怎么办呢?我们可以将它的构造器改为私有的(可以么?可以!)
2.构造器编程私有,那就只能它自己的实例可以调用构造器了,但是调用构造器之前哪来的实例(鸡生蛋问题)?
3.错了,可以使用静态方法去调用私有的构造器。剩下的就是调用前判断下对象是否存在了。如下图:
这里uniqueInstance要定义为静态变量,这样它的生命周期和类的生命周期一样,而不是和实例变量一样生命周期是对象的生命周期。
这样调用getInstance方法时先判断uniqueInstance是否为空,为空则创建对象,并将uniqueInstance指向该对象,方法返回该引用。下次getInstance被调用的时候,uniqueInstance已经不是空了,所以直接返回之前new出来的对象,这样每次调用getInstance都返回同一个对象。
来看看官方对单例模式的定义:
确保一个类只有一个实例,并提供一个全局访问点。
故事好像到这里该结束了。no。这只是在单线程的情况下,一个类使用这种方式确实只可以产生一个对象,但是多线程情况呢?当两个线程同时访问getInstance方法时,uniqueInstance可都是空的哦。。
不用怕,java对于多线程带来的资源使用问题早已经有办法。我们可以使用同步给getInstance方法加锁:
看,当一个线程进入getInstance方法时,另一个线程只能在门等待。直到第一个线程执行完方法后,第二个线程进入getInstance方法时uniqueInstance已经不为空了。所以也得到了我们想要的结果。
但是这样每次调用getInstance方法都要使用同步,这很消耗系统开销的哦。对此我们有三种不同的方案实现:
1.假如对性能要求不高的应用程序来说,那么直接使用上面同步的方法就行了。
2.如果对性能要求高的话,可以在类加载入虚拟机的时候就将对象new出来,像这样:
这样确保在任何线程进入的时候就已经有对象了。
3.使用“双重检查加锁”,只在对象不存在的时候使用同步一次。
可能大家有疑问为什么有两次执行if(uniqueInstance == null)。原因是这样的,当第一次两个线程都通过第一个if(uniqueInstance == null)时,因为同步,只有一个线程可以进入synchronized后的代码,当第一个线程执行完方法后,第二个线程进入synchronized后的代码时如果不对uniqueInstance进行判断,那么线程照样会执行new对象的代码。
- 调侃《Head First 设计模式》之单例模式
- 调侃《Head First 设计模式》之工厂模式(二)
- 调侃《Head First 设计模式》之命令模式
- 调侃《Head first设计模式》之适配器模式
- 调侃《Head First设计模式》之外观模式
- 调侃《Head First设计模式》之模板方法模式
- 调侃《First head 设计模式》之状态模式篇
- 调侃《Head First设计模式》之总结篇
- 调侃《Head First设计模式》之总结篇
- head first设计模式之单例模式 c++解读
- 《Head First 设计模式》之单例模式
- 《head first 设计模式》之单例模式
- Head First设计模式之单例模式
- Head First设计模式-单例模式
- 调侃《Head First设计模式》之迭代器和组合模式(一)
- 调侃《Head First设计模式》之迭代器和组合模式(二)
- head first 之 单例模式
- 《Head First 设计模式》单件模式
- 《CTCI》2.1 移除未排序链表中的重复结点
- 计算string对象长度要使用strlen()和c_str()
- 安卓ColorStateList文件——文字的动作效果
- 第2章 C语言概述
- jdk1.6学习笔记
- 调侃《Head First 设计模式》之单例模式
- 使用printf输出各种格式的字符串
- JS 您还可以输入多少个字
- JAVA写入MySQL数据提示[ERROR 1366 (HY000):错误异常解决方案
- android 动态调整RelativeLayout布局控件的相对位置 layout_toLeftOf 之类的
- 如何检查表空间和表占用率
- LPVOID和PVOID的区别是什么
- 腾讯笔试题
- 直线交点