面向对象的设计模式,是在特定场景下常用而有效的设计,优点在于代码有效,易读,有利于程序员复用,维护。
单例模式 (Singleton)
单例模式是23种GoF设计模式中的一种,主要用来解决以下问题:
- 如何保证一个类只有一个实例?
- 如何让访问单个实例变得简单?
- 如何让类控制实例化
- 如何限制一个类的实例数量?
单例模式使用下列方式解决上述问题:
- 隐藏构造器
- 定义一个public static operation ( getInstance() ) 来返回单例
特点:这种设计模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点
使用场景:
1. abstract factory,builder和prototype patterns 可以利用singletons 来实现
2. Facade objects通常就是 singletons
3. State objects通常也是singletons
4. 用于全局变量,因为不会污染全局namespace,而且允许延迟装载资源。
案例:例如服务器的配置文件由唯一的单例类实例来读取,其他类再通过单例类实例来获取配置信息。
缺陷:多线程下,并发线程对单例类的实例化可能产生多个实例。因此需要为实例化指示变量加上一个互斥锁。
单例几种写法
1. 饿汉(静态常量)
/*
* A simple implementation of singleton pattern
* using final static instance
*/
public class SingletonH {
//ensure only one instance of the singleton class ever exists
private final static SingletonH INSTANCE = new SingletonH();
private SingletonH(){}
//provide global access to that instance
public static SingletonH getInstance(){
return INSTANCE;
}
}
饿汉直接预加载静态常量,方便但是占用资源。
2. 饿汉(静态代码块)
/*
* A simple implementation of Singleton pattern
* by using a static code block
*/
public class SingletonHSB{
private static Singleton instance;
static {
instance = new SingletonHSB();
}
private SingletonHSB(){}
public static SingletonHSB getInstance(){
return instance;
}
}
3. 静态内部类
/*
* a simple implementation of Singletons by using
* a static inner class
*
*/
public class SingletonSIC {
private SingletonSIC(){}
private static class SingletonInstance {
private static final SingletonSIC INSTANCE = new SingletonSIC();
}
public static SingletonSIC getInstance(){
return SingletonInstance.INSTANCE;
}
}
静态内部类实现延迟加载,因为只有当调用其静态成员时,才加载。
4. 枚举类
/*
* a simple implementation of Singletons by using
* an enum INSTANCE
*/
public enum SingletonEnum {
INSTANCE;
public void whateverMethod(){
}
}
5. 双重检查
/* a simple implmentation of singletons by using
* double check if an instance already exists
*/
public class SingletonDC{
private volatile static SingletonDC singleton;
private SingletonDC(){}
public static SingletonDC getInstance(){
if (singleton == null){
synchronized (Singleton.class){
if (singleton == null){
singleton = new SingletonDC();
}
}
}
return singleton;
}
}
双重检查减少了同步的部分性能损耗,当多个线程检查到实例已初始化后,直接返回实例。
为了让实例变量的初始化对多个线程同步可见,我们还需要使用volatile修饰变量