一、什么是单例模式:
单例模式是一种确保了一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。被实例化的类称为单例类。
二、单例模式的特点:
单例类只有一个实例。
单例类必须自行创建自己唯一的实例。
单例类必须给其他对象提供这个实例。
注意:虽然单例模式和单例类限定了只能有一个实例,但是作为单例模式的推广,可以推广到任意且有限多个实例的情况,这时候被称为多例模式和多例类。
三、单例模式的结构:
一个单例类只有一个实例。
单例类的实例持有对自己的引用。
四、单例模式的实例化:
Java中单例模式有着自己的特点,具体表现在单例类的实例化上:
饿汉式单例类(静态常量):
1 /**
2 * 饿汉式(静态常量)3 *4 *@authorZhouDX5 *@since2019/3/4 22:12:286 */
7 public classHungerSingleton {8 private static final HungerSingleton SINGLETON= newHungerSingleton();9
10 /**
11 * 私有的默认构造函数12 */
13 privateHungerSingleton() {14 }15
16 /**
17 * 静态工厂方法18 */
19 public staticHungerSingleton getInstance() {20 returnSINGLETON;21 }22 }
Java中最简单的单例类,类的单例被声明为静态变量,在类加载时,调用类的私有构造函数,静态变量被实例化。
特点:
1.类的构造函数私有,避免了外界利用构造函数创建任意多的实例。
2.且由于构造函数私有,类不能被继承。
3.只能通过静态方法getInstance()来获取类的实例对象。
优点:
类装载的时候就完成实例化。避免了线程同步问题。
缺点:
在类装载的时候就完成实例化,没有达到延迟加载的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。
饿汉式单例类(静态代码块):
1 /**
2 * 饿汉式单例类(静态代码块)3 *4 *@authorZhouDX5 *@since2019/3/13 22:45:246 */
7 public classHungerSington_StaticCode {8 private staticHungerSington_StaticCode singleton;9
10 /**
11 * 静态代码块12 */
13 static{14 singleton= newHungerSington_StaticCode();15 }16
17 /**
18 * 私有构造函数19 */
20 privateHungerSington_StaticCode() {21 }22
23 /**
24 * 获取单例类实例的唯一接口25 *26 *@return单例类27 */
28 public staticHungerSington_StaticCode getInstance() {29 returnsingleton;30 }31 }
特点:
将单例类放在静态代码块中,也是类在加载时执行静态代码块中的代码,完成类的实例化,优缺点同静态常量。
汉懒式单例类(线程不安全):
1 /**
2 * 懒汉式(线程不安全)[不可用]3 *4 *@authorZhouDX5 *@since2019/3/13 22:52:246 */
7 public classLazySingleton_ThreadUnsafe {8 private staticLazySingleton_ThreadUnsafe singleton;9
10 /**
11 * 获取单例类实例12 *13 *@return单例类实例14 */
15 public staticLazySingleton_ThreadUnsafe getInstance() {16 if (null ==singleton) {17 singleton = newLazySingleton_ThreadUnsafe();18 }19
20 returnsingleton;21 }22 }
特点:
1.达到了延迟加载的目的,只有在单例类第一次被引用时将自己实例化。
2.在单线程下使用。
缺点:
在多线程的环境中,多个线程同时进入if (null == singleton) {},还未执行singleton = new LazySingleton_ThreadUnsafe()时,另一个线程也恰好进入这里,就会造成单例类多个实例,线程不安全,不可以再多线程的环境下使用。
懒汉式(线程安全,同步方法)
1 /**
2 * 懒汉式(线程安全,同步方法)3 *4 *@authorZhouDX5 *@since2019/3/4 22:23:026 */
7 public classLazySingleton {8 private static LazySingleton lazySingleton = null;9
10 /**
11 * 构造函数12 */
13 privateLazySingleton() {14 }15
16 /**
17 * 静态工厂方法,返回懒汉式实力类的唯一实例18 *19 *@return
20 */
21 public static synchronizedLazySingleton getInstance() {22 if (lazySingleton == null) {23 return lazySingleton = newLazySingleton();24 }25 returnlazySingleton;26 }27 }
特点:
使用了synchronized对静态工厂类方法进行了同步,安全处理多线程的问题。
缺点:
每个线程执行getInstance()方法都要进行同步,大大降低了执行的效率。且getInstance()只需要实例化一次就可以。
懒汉式(线程不安全,同步代码块)
1 /**
2 * 懒汉式(线程安全,同步代码块)3 *4 *@authorZhouDX5 *@since2019/3/13 23:12:086 */
7 public classLaSingleton_ThreadUnsafe {8 private staticLaSingleton_ThreadUnsafe singleton;9
10 /**
11 * 静态构造方法12 */
13 privateLaSingleton_ThreadUnsafe() {14 }15
16 /**
17 * 获取单例类实例18 *19 *@return单例类实例20 */
21 public staticLaSingleton_ThreadUnsafe getInstance() {22 if (null ==singleton) {23 synchronized (LaSingleton_ThreadUnsafe.class) {24 singleton = newLaSingleton_ThreadUnsafe();25 }26 }27 returnsingleton;28 }29 }
特点:
同步产生实例的代码块。
缺点:
假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。
懒汉式(双重检查):
1 /**
2 * 懒汉式(双重检查):3 *4 *@authorZhouDX5 *@since2019/3/13 23:24:276 */
7 public classLazySingleton_DoubleCheck {8 private static volatileLazySingleton_DoubleCheck singleton;9
10 /**
11 * 静态构造方法12 */
13 privateLazySingleton_DoubleCheck() {14 }15
16 /**
17 * 获取单例类实例18 *19 *@return单例类实例20 */
21 public staticLazySingleton_DoubleCheck getInstance() {22 if (null ==singleton) {23 synchronized (LazySingleton_DoubleCheck.class) {24 singleton = newLazySingleton_DoubleCheck();25 }26 }27 returnsingleton;28 }29 }
特点:
1.进行了两次if (singleton == null)检查,保证了线程安全。
2.实例化代码只执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象。
优点:
程安全;延迟加载;效率较高。
静态内部类:
1 /**
2 * 静态内部类3 *4 *@authorZhouDX5 *@since2019/3/13 23:28:586 */
7 public classSingleton_StaticInnerClass {8 /**
9 * 私有构造方法10 */
11 privateSingleton_StaticInnerClass() {12 }13
14 /**
15 * 静态内部类16 */
17 private static classSingletonInstance {18 private static final Singleton_StaticInnerClass SINGLETON = newSingleton_StaticInnerClass();19 }20
21 /**
22 * 获取单例类实例23 *24 *@return单例类实例25 */
26 private staticSingleton_StaticInnerClass getInstance() {27 returnSingletonInstance.SINGLETON;28 }29 }
特点:
类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
优点:
避免了线程不安全,延迟加载,效率高。
枚举:
1 /**
2 * 枚举3 *4 *@authorZhouDX5 *@since2019/3/13 23:33:436 */
7 public enumSingleton_Enum {8 SINGLETON;9
10 public voidwhateverMethod() {11 }12 }
特点:
系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
优点:
当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new,可能会给其他开发人员造成困扰,特别是看不到源码的时候。
懒汉式单例类与饿汉式单例类的比较:
饿汉式单例类在自己被加载时将自己实例化,即便加载器是静态的,依旧在加载时实例化自己;懒汉式单例类在第一次被引用时将自己实例化,如果加载器是静态的,懒汉式单例类被加载时不会将自己实例化。
从资源利用角度讲,懒汉式单例类的资源利用效率高点;从速度和反应时间来讲,饿汉式的好点。