目录
单例模式
单例模式是结构最简单的设计模式,在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以确保系统中的一个类只有一个实例而且该实例易于被外界访问,从而方便对实例个数进行控制,节约系统资源.
单例模式概述
单例模式:确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例.
单例模式是一种对象创建型模式.单例模式有3个要点:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例.
单例模式结构
单例模式只包含一个单例角色,也就是Singleton.
单例模式实现
public class Singleton{
private static Singleton instance = null; //静态私有成员变量
//私有构造函数
private Singleton(){
}
//静态公有工厂方法,返回唯一实例
public static Singleton getInstance(){
if(instance==null)
instance = new Singleton();
return instance;
}
}
在单例模式的实现过程中需要注意以下3点:
- 单例类构造函数的可见性为private.
- 提供一个类型为自身的静态私有成员变量.
- 提供一个公有的静态工厂方法.
饿汉式单例与懒汉式单例
饿汉式单例类在定义静态变量的时候实例化单例类,因此在类加载时单例对象就已创建.由Java虚拟机负责安全的创建对象,因此没有多线程下的安全问题.
public class EagerSingleton{
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton(){}
public static EagerSingleton getInstance(){
return instance;
}
}
懒汉式单例类在第一次被引用时将自己实例化,在懒汉式单例类被加载时不会将自己实例化.这种技术又称为延迟加载技术,即需要的时候再加载实例.为了避免多个线程同时调用getInstance()方法,可以使用关键字synchronized,代码不贴了,这种方法效率低,于是改进,减小安全区的范围,将同步方法变为同步代码块,但是这种方法还是有安全问题,所以提出了双重检查锁定(DCL),代码如下:
public class LazySingleton{
private volatile static EagerSingleton instance = null;
private LazySingleton(){}
public static LazySingleton getInstance(){
//第一重判断
if(instance==null){
//锁定代码块
synchronized(LazySingleton.class){
//第二重判断
if(instance==null){
instance = new LazySingleton(); //创建单例实例
}
}
}
return instance;
}
}
由于volatile关键字会屏蔽Java虚拟机所做的一些代码优化,可能会导致系统的运行效率降低,因此即使使用双重检查锁定来实现单例模式也不是一种完美的实现方式.
使用静态内部类实现单例模式
在Java语言中可以通过Initialization on Demand Holder(IoDH)技术来实现单例模式
public class Singleton{
private Singleton(){}
private static class HolderClass{
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return HolderClass.instance;
}
}
通过使用IoDH既可以实现延迟加载,又可以保证线程安全,不影响系统性能,不失为一种最好的Java语言单例模式的实现方式.但是与编程语言本身特性相关,很多面向对象语言并不支持IoDH.
单例模式优缺点与适用环境
单例模式优点:
- 提供了对唯一实例的可受控访问并可以节约系统资源.
- 允许可变数目的实例.(自行提供指定数目实例对象的类可称为多例类)
单例模式缺点:
- 因为缺少抽象层而难以扩展,且单例类职责过重,将太多功能耦合在一起.
单例模式适用环境:
- 系统只需要一个实例对象.
- 客户调用类的单例实例只允许使用一个公共访问点.