单件模式用来创建独一无二的,只能有一个实例的对象的入场券
利用单件模式,我们可以在需要的时候才创建对象。如何实现呢?私有化该类的构造器,并在内部实例化。提供一个静态方法getInstance(),返回该类的实例。返回前,先检查,为实例化,则先实例化。这样,只有在第一次调用时,才需要实例化的对象,后面返回的都是同一个。
但是这会存在一个问题。多线程时,可能会出现多个实例 。有人提出将静态方法加锁。。
那么,该如何改善多线程呢?
- 如果getInstance()的性能对应用程序不是很关键,就什么都别做。同步一个方法可能造成程序执行效率下降100倍。因此,如果将getInstance()的程序使用在频繁运行的地方,你可能就得重新考虑了。
- 使用“急切”创建实例,而不用延迟实例化的做法。利用这个做法,我们依赖JVM在加载这个类时马上创建唯一的单件实例。JVM保证在任何线程访问uniqueInstance静态变量之前,一定先创建此实例。
public class Singleton {
// 在静态初始化器(static initializer)中创建单件。这段代码保证了线程安全(thread state)
private static Singleton uniqueInstance = new Singleton();
private Singleton(){}
public static Singleton getInstance() {
return uniqueInstance;
}
}
- 用“双重检查加锁”,在getInstance()中减少使用同步。利用双重检查锁(double-checked locking),首先检查是否实例已经创建了,如果尚未创建,“才”进行同步。这样一来,只有第一次会同步,这正是我们想要的。
public class Singleton {
// 在静态初始化器(static initializer)中创建单件。这段代码保证了线程安全(thread state)
// volatile关键词确保:当uniqueInstance变量被初始化Singleton实例时,
// 多个线程正确地处理uniqueInstance变量
private volatile static Singleton uniqueInstance;
private Singleton(){}
public static Singleton getInstance() {
if(uniqueInstance == null){
// 检查实例,如果不存在,就进入同步区块
synchronized (Singleton.class){
// 注意,只有第一次才彻底执行这里的代码
if(uniqueInstance == null) {
// 进入区块后,再检查一次。如果仍是null,才创建实例
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}