Singleton Pattern 简介
定义
确保一个类只有一个实例,并提供全局访问点。
用途
- 有一些对象我们只需要一个,比如:线程池(threadpool)、缓存(cache)、注册表设置对象(registry setting),确保程序中使用的全局资源只有一份。
- 管理共享资源
类图
处理多线程
如果 getInstance() 的性能对应用程序不是很关键,可以用下面的方式:
public class Singleton {
private static Singleton uniqueInstance;
private Singleton(){}
/**
* 通过增加 synchronized 关键字到 getInstance 中,我们迫使每个线程在进入这个方法之前,
* 要先等候别的线程离开该方法。
* @return
*/
public static synchronized Singleton getInstance(){
if (uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
这样可以解决问题,但是同步降低了性能。还有一点:只有第一次执行此方法时,才真正需要同步,换句话说,一旦设置好 uniqueInstance 变量,就不再需要同步这个方法了,之后每次调用这个方法,同步都是一种负担。
使用急切创建实例,而不用延迟实例化的做法(饿汉式)
如果应用程序总是创建并使用单例实例,或者在创建和运行时方面的负担不太繁重,可以用这种方式:
public class Singleton {
//在静态初始化器中创建单例,这段代码保证了线程安全
private static Singleton uniqueInstance = new Singleton();
private Singleton(){}
public static synchronized Singleton getInstance(){
return uniqueInstance;
}
}
这样,JVM在加载这个类时马上创建此唯一的单例,保证了在任何线程访问 uniqueInstance 静态变量之前,一定先创建此实例。
双重检查加锁,在 getInstance() 中减少使用同步
如果性能是重点,这个方法会大大地减少 getInstance() 的时间耗费。
public class Singleton {
//volatile 关键字确保,当 uniqueInstance 变量被初始化成 Singleton 实例时,
//多个线程正确地处理 uniqueInstance 变量
private volatile static Singleton uniqueInstance;
private Singleton(){}
/**
* 检查实例,如果不存在,则进入同步块
* @return
*/
public static synchronized Singleton getInstance(){
if (uniqueInstance == null){
//只有第一次才彻底执行这里的代码
synchronized (Singleton.class){
//进入这里后,在检查一次,如果仍然是 null 才创建
if (uniqueInstance == null){
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}