一篇文章讲清楚单例模式

416 阅读4分钟

前言:

作者:韩数

Github:github.com/hanshuaikan…

时间:2019-01-26

Jdk版本:1.8

定义:

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

适用范围:

一个全局使用的类频繁地创建与销毁。当某些如打印机程序只需要一个操作实例的时候(多个实例同时调用一台打印机打印文件可能会出现问题)

优/缺点

优点:

在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。

避免对资源的多重占用(比如写文件操作)

缺点:

没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化

前提引入:

单例模式是设计模式中较为简单的设计模式之一,同时又在实际的开发过程中广泛使用的一种设计模式,本次,我们将从基础版开始,使用4种不同的方式来实现单例模式。

代码实战:

1.基础版

这种方式实现的单例模式是我们日常使用较多的设计模式,采用了延迟加载来减少系统资源不必要的开支,但如果多个线程同时调用 getInstance 方法获取Singleton的实例时,可能会出现问题。

优/缺点:

优点:易于实现

缺点:线程不安全,在多线程下不能正常工作

代码如下:

/***
 * 
 * @author 韩数
 * 一般单例模式实现,采用延迟加载方式实现
 *
 */

public class Singleton {
	
	private static Singleton uniqueInstance;
 
	private Singleton() {}
 
	public static Singleton getInstance() {
		if (uniqueInstance == null) {
			uniqueInstance = new Singleton();
		}
		return uniqueInstance;
	}
 
}

2.线程安全基础版:

代码如下:

优/缺点:

优点:线程安全,没有加锁,执行效率会高一点

缺点:容易产生垃圾对象,类加载时就初始化,浪费内存

/***
 * 
 * @author 韩数
 * 常用的单例模式实现
 * 线程安全,不足之处,可能会损失一部分性能,非延迟加载
 *     
 */


public class Singleton {
	
	//在类初始化的时候就实例化对象,所以不存在多线程的安全问题
	private static Singleton uniqueInstance = new Singleton();
 
	private Singleton() {}
 
	public static Singleton getInstance() {
		return uniqueInstance;
	}
}
3.线程安全加强版:

优/缺点:

优点:线程安全,延迟加载

缺点:必须加锁,效率比较低

代码如下:

/**
 * 
 * @author 韩数
 * 线程安全方式实现单例模式,缺点是,每次都会调用synchronized的关键字修饰的方法,会损失一定的性能
 *
 */

public class Singleton {
	
	
	private static Singleton uniqueInstance;
 
	private Singleton() {}
 
	//synchronized修饰该方法,保证每次只有一个线程进入该方法,从而避免产生多个Singleton对象实例。
	public static synchronized Singleton getInstance() {
		if (uniqueInstance == null) {
			uniqueInstance = new Singleton();
		}
		return uniqueInstance;
	}
}

4.线程安全旗舰版:

双检锁/双重校验锁(DCL,即 double-checked locking): 可以在保证安全性的情况下,兼顾高性能

优/缺点:

优点:线程安全,延迟加载,执行效率高

缺点:实现难度比前几种稍显复杂

关于 volatile 关键字,感兴趣的伙伴可以去这个博客看一下,写得非常好

www.cnblogs.com/dolphin0520…

代码如下:

/***
 * 
 * @author 韩数
 * 线程安全,延迟加载方式实现单例模式
 *
 */

public class Singleton {
	
	private volatile static Singleton uniqueInstance;
	
	// 一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
	//保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是       立即可见的。
	//禁止进行指令重排序。
 
	private Singleton() {}
 
	public static Singleton getInstance() {
		//延迟加载
		if (uniqueInstance == null) {
			//加线程锁
			synchronized (Singleton.class) {
				if (uniqueInstance == null) {
					uniqueInstance = new Singleton();
				}
			}
		}
		return uniqueInstance;
	}
}

总结:

本篇文章较为简单的阐述了单例模式的优缺点,使用场景,以及4种不同的实现方式,当然,现实生活中,单例模式的实现绝非只有本文中的4种,如果对单例模式的其他实现方式感兴趣的话,大家可以去互联网上查询相关的资料。

写在最后:

欢迎大家给小星星,您的星星是我写下去的不竭动力!

源码部分请移步本人Github下载:

Github地址:

Github:github.com/hanshuaikan…

参考资料:

菜鸟教程:www.runoob.com/design-patt…

Head frist of 设计模式