实现SingleTton模式
一、题目
设计一个类,我们只能生成该类的一个示例。
只能生成一个实例的是为了实现Singleton
(单例)模式的类型,设计模式在面向对象程序设计中起着举足轻重的作用,在面试过程中公司都喜欢问一些与设计模式相关的问题。在常用的设计模式中,Singleton
是唯一一个能够用几十行代码完整实现的模式。因此,写一个Singleton
的类型是一个很常见的面试题。
二、参考解法
1、懒汉式——线程安全
1 | public class Singleton{ |
该解法在单线程的时候共工作正常,但在多线程的情况下不适用。设想如果两个线程同时运行到判断instance是否为null的if语句,并且instance的确没有创建时,那么两个线程都会创建一个实例,此时就不满足单例模式的要求。
2、懒汉式——线程安全
1 | public class Singleton{ |
该解法在多线程环境下使用正常,但是并不完美。在执行过程中,每次都需通过getInstance()
得到Singleton实例,并且在此方法中都会加上同步锁,而加锁是一个非常耗时的操作,在没有必要的时候应尽量避免
3、双重校验锁——线程安全
1 | public class Singleton{ |
该解法只有当instance
为null
即没有创建时,需要加锁操作。当instance
已经创建出来之后,则无需加锁。相比于解法二大大提高了效率,但是代码实现起来比较复杂,容易出错。
instance 采用 volatile 关键字修饰也是很有必要的。instance = new Singleton();
这段代码其实是分为三步执行。volatile禁止指令重排。
- 分配内存空间
- 初始化对象
- 将 uniqueInstance 指向分配的内存地址
4、饿汉式——线程安全
1 | public class Singleton{ |
利用静态属性、静态代码块的性质,确保只在加载时调用一次。该段代码非常简洁地实现了功能,但是调用静态构造函数地时机并不是由程序员掌控,而是由JVM运行时发现第一次使用一个类型的时候自动调用该类型的静态构造函数。即实例instance
并不是第一次调用属性Singleton.getInstance
时创建,而是在第一次用到Singleton
时创建。(降低内存的使用效率)
5、静态内部类——按需创建
1 | public class Singleton{ |
6、枚举
1 | public enum Singleton { |
单例模式的最佳实践,它实现简单,并且在面对复杂的序列化或者反射攻击的时候,能够防止实例化多次。