定义:
确保一个类只有一个实例,并提供一个全局访问点
经典单件模式
public class Singleton{
//利用一个静态变量记录Singleton类的唯一实例
private static Singleton uniqueInstance;
//将构造器声明为私有的,只有类内才能调用
private Singleton(){}
//用getInstance()方法实例化对象,并返回这个实例--提供的全局访问点
public static Singleton getInstance(){
if(uniqueInstance == null){
//如果我们不需要这个实例,它就永远不会产生("延迟实例化")
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
但是在多线程的情况下,会出现两个线程都判断uniqueInstance为null,从而返回两个不同对象。故这种实现单件的方式不是线程安全的。
多线程与单件
法1:同步getInstance
private static Singleton uniqueInstance;
private Singleton(){}
//通过增加synchronized关键字到getInstance()方法中我们迫使每个线程在进入方法之前,要等候别的线程离开这个方法
public static synchronized Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
//But:只有第一次执行此方法时,才真正需要同步,一旦设置好uniqueInstance变量,就不再需要同步这个方法了,之后每次调用这个方法,同步都是一种累赘
法2:急切实例化
//在静态初始化器中创建单件,保证了线程安全
private static Singleton uniqueInstance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
//已经有实例了,直接使用
return uniqueInstance;
}
//利用这种做法我们依赖JVM在加载这个类时,马上创建此唯一的实例,
法3:双重检查加锁
private volatile static Singleton uniqueInstance;
private Singleton(){}
public static Singleton getInstance(){
//检查实例如果不存在,就进入同步区块,只有第一次才彻底执行这里的代码
if(uniqueInstance == null){
synchronized (Singleton.class) {
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
//volatile关键字确保当uniqueInstance初始化成Singleton实例时,多个线程正确的处理uniqueInstance变量。