有时候某些对象咱们只须要一个,如:线程池、缓存、对话框等等,对于这类对象咱们只能有一个实例,若是我web
们制造出多个实例,就会致使不少问题产生。设计模式
可是咱们怎样才能保证一个类只有一个实例而且可以便于访问?这里咱们想到了全局变量,全局变量确实是能够缓存
保证该类能够随时访问,可是它很难解决只有一个实例问题。最好的办法就是让该自身来负责保存它的惟一实例。这安全
个类必需要保证没有其余类来建立它。这里咱们能够将其构造方法私有化。即多线程
1 Public MyClass{ 2 PrivateMyClass(){} 3 }
含有私有化构造器的类就能保证它不能被其余类实例化了。可是咱们如何来获取这个实例化类呢?提供一个方法性能
用于返回该类的实例对象便可实现。spa
1 public class MyClass { 2 private MyClass(){ 3 4 } 5 6 public static MyClass getInstance(){ 7 return new MyClass(); 8 } 9 }
1、基本定义 线程
经过上面简单介绍,咱们能够对单例模式有一个简单的认识。所谓单例模式就是确保某一个类只有一个实例,并设计
且提供一个全局访问点。code
从上面能够看出单例模式有以下几个特色:
1、它只有一个实例。
2、它必需要自行实例化。
3、它必须自行想整个系统提供访问点。
2、模式结构
单例模式能够说是最简单的设计模式了,它仅有一个角色Singleton。
Singleton:单例。
3、模式实现
1 public class Singleton { 2 //利用静态变量来记录Singleton的惟一实例 3 private static Singleton uniqueInstance; 4 5 /* 6 * 构造器私有化,只有Singleton类内才能够调用构造器 7 */ 8 private Singleton(){ 9 10 } 11 12 public static Singleton getInstance(){ 13 if(uniqueInstance == null){ 14 uniqueInstance = new Singleton(); 15 } 16 17 return uniqueInstance; 18 } 19 20 }
在《Head First》有这样一个场景,就是说有两个线程都要执行这段代码,颇有可能会产生两个实例对象。以下图:
这里有三种解决方案。
第1、 使用synchronized来处理。也就是说将getInstance()方法变成同步方法便可。
1 public class Singleton { 2 //利用静态变量来记录Singleton的惟一实例 3 private static Singleton uniqueInstance; 4 5 /* 6 * 构造器私有化,只有Singleton类内才能够调用构造器 7 */ 8 private Singleton(){ 9 10 } 11 12 public static synchronized Singleton getInstance(){ 13 if(uniqueInstance == null){ 14 uniqueInstance = new Singleton(); 15 } 16 17 return uniqueInstance; 18 } 19 20 }
第2、 直接初始化静态变量。这样就保证了线程安全。
1 public class Singleton { 2 /* 3 * 利用静态变量来记录Singleton的惟一实例 4 * 直接初始化静态变量,这样就能够确保线程安全了 5 */ 6 private static Singleton uniqueInstance = new Singleton(); 7 8 /* 9 * 构造器私有化,只有Singleton类内才能够调用构造器 10 */ 11 private Singleton(){ 12 13 } 14 15 public static Singleton getInstance(){ 16 return uniqueInstance; 17 } 18 19 }
第3、 用“双重检查加锁”,在getInstance()中减小使用同步。
1 public class Singleton { 2 /* 3 * 利用静态变量来记录Singleton的惟一实例 4 * volatile 关键字确保:当uniqueInstance变量被初始化成Singleton实例时, 5 * 多个线程正确地处理uniqueInstance变量 6 * 7 */ 8 private volatile static Singleton uniqueInstance; 9 10 /* 11 * 构造器私有化,只有Singleton类内才能够调用构造器 12 */ 13 private Singleton(){ 14 15 } 16 17 /* 18 * 19 * 检查实例,若是不存在,就进入同步区域 20 */ 21 public static Singleton getInstance(){ 22 if(uniqueInstance == null){ 23 synchronized(Singleton.class){ //进入同步区域 24 if(uniqueInstance == null){ //在检查一次,若是为null,则建立 25 uniqueInstance = new Singleton(); 26 } 27 } 28 } 29 30 return uniqueInstance; 31 } 32 33 }
在这里是首先检查是否实例已经建立了,若是还没有建立,才会进行同步。这样一来。只有第一次会同步。
4、模式优缺点
优势
1、节约了系统资源。因为系统中只存在一个实例对象,对与一些须要频繁建立和销毁对象的系统而言,单
例模式无疑节约了系统资源和提升了系统的性能。
2、由于单例类封装了它的惟一实例,因此它能够严格控制客户怎样以及什么时候访问它。
缺点
1、因为单例模式中没有抽象层,所以单例类的扩展有很大的困难。
2、单例类的职责太重,在必定程度上违背了“单一职责原则”。
5、模式使用场景
下列几种状况可使用单例模式。
1、系统只须要一个实例对象,如系统要求提供一个惟一的序列号生成器,或者须要考虑资源消耗太大而只容许建立一个对象。
2、客户调用类的单个实例只容许使用一个公共访问点,除了该公共访问点,不能经过其余途径访问该实例。
6、总结
1. 单例模式中确保程序中一个类最多只有一个实例。
2. 单例模式的构造器是私有了,并且它必需要提供实例的全局访问点。
3. 单例模式可能会由于多线程的问题而带来安全隐患。