单例设计模式
菜鸟教程设计模式:https://www.runoob.com/design-pattern/design-pattern-tutorial.html
0 知识点的引出背景
在我们的系统中,有一些对象其实我们只需要一个,比如说:线程池、缓存、对话框、注册表、日志对象、充当打印机、显卡等设备驱动程序的对象。事实上,这一类对象只能有一个实例,如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常、资源使用过量、或者不一致性的结果。
1 单例模式概念
- 单例模式是指在一个系统中,一个类有且只有一个对象实例。
- 单例模式的实现:
- 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。;
- 在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型 ;
- 定义一个静态方法返回这个唯一对象 ;
2 单例模式的好处
- 对于频繁使用的对象,可以省略创建对象所花费的时间;
- 由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间 ;
3 单例模式的分类:懒汉式 vs 饿汉式
① 饿汉式 - 线程安全
饿汉式的单例模式在程序初始化的时候即创建了对象,在需要的时候可以直接返回该对象实例。 代码如下:
饿汉式的特点:
- 是线程安全的;
- 饿汉式天生就是线程安全的:https://blog.csdn.net/Aikin_Tony/article/details/106220242
- 优点:简单,容易实现
- 缺点:程序在初始化时就创建了对象,无论这个对象是否使用,他都占据了内存空间,可能会造成内存资源的浪费;
②懒汉式 - 线程不安全
懒汉式的单例模式是在真正需要使用到的时候,才会去创建实例对象。 代码如下:
懒汉式的特点:
- 因为没有加锁,所以是线程不安全的;
- 线程不安全的原因:https://blog.csdn.net/Mars_idea/article/details/80724404
- 优点:只有在使用时才会创建对象,一定程度上节省了内存资源;
③ 线程安全的懒汉式
特点:
- 加锁后,线程安全;
- 由于加锁后效率太低,实际多线程中不适用。
- 这里有个很大(至少耗时比例上很大)的性能问题。除了第一次调用时是执行了Single3的构造函数之外,以后的每一次调用都是直接返回s对象。返回对象这个操作耗时是很小的,绝大部分的耗时都用在synchronized修饰符的同步准备上,因此从性能上来说很不划算。
④ 多线程环境下的懒汉式(DCL,双检锁+volatile实现) ---> 建议使用
我们可以通过加入synchronized内部锁来解决多线程环境下懒汉式的线程安全问题 。代码如下:
第二步和第三步可能会发生重排序,导致引用型变量指向了一个不为null但是也不完整的对象。所以,在多线程下上述的代码会返回一个不完整的对象。根据前面章节所学的内容,我们需要加入一个volatile关键字来禁止指令重排序。
代码中synchronized(SingleClass.class)的说明:代码块锁、静态方法快类锁
参考链接:http://bbs.itheima.com/thread-111816-1-32.html
参考链接:https://www.cnblogs.com/wpf-7/p/9639671.html
特点:
- 加锁后,线程安全;
- 因为采用双锁机制,效率上比③要高;
- 参考链接:https://www.cnblogs.com/codingmengmeng/p/9846131.html
4 单例模式的应用场景
以下都是单例模式的经典使用场景:
1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
2.控制资源的情况下,方便资源之间的互相通信。如线程池等。
单例模式的使用场景:创建一个对象需要消耗太多的资源或者在一个系统中不适合创建多个对象实例的情况下,我们可以采用单例模式设计实现。
举例:
- Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗?
- windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
- 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
来源:oschina
链接:https://my.oschina.net/u/4419899/blog/4299064