单件模式的经典实现:
public class Singleton {
//利用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
//构造方法声明为私有
private Singleton() {}
//若uniqueInstance为空,则不存在实例,则利用私有的构造器产生一个实例,
//并将它复制到uniqueInstance静态变量中;若不为空,则说明已经有了实例,直接返回。
public static Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// other useful methods here
}
注意,如果我们不需要这个实例,就永远不会产生,这就是“延迟实例化”。
线程不安全。
定义:
确保一个类只有一个实例,并提供一个全局访问点。
类图:

经典单件模式存在问题,它是线程不安全的。当两个或以上调用
getInstance()
方法的时候可能出现线程不安全的问题。
处理线程不安全的方法:
使用synchronized关键字
将getInstance()
方法改为:
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
该方法的不足之处在于:同步会降低性能,我们只需要第一次执行
getInstance()
方法的时候同步。这个方法使得每次调用这个方法都会同步,比较累赘。
解决方法:
- 如果可以接受同步带来的性能影响,则直接忽略它。
- 使用“急切”创建实例。
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
// other useful methods here
}
JVM加载这个类时马上创建唯一的单件实例,保证任何线程访问
uniqueInstance
静态变量之前,一定先创建此实例。前提是程序总是创建并使用单件实例,或者在创建和运行时负担不太繁重。
- 用“双重检查加锁”,首先检查是否实例已经创建了,如果尚未创建,“才”进行同步,这样一来,只有第一次才会同步。
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
//检查实例,如果不存在,就进入同步区块
if (uniqueInstance == null) {
synchronized (Singleton.class) {
//进入区块后,再检查一次。如果仍是null,才创建实例
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
volatile
关键字可以从可见性和有序性两方面保证线程安全。(此方法不适用于Java 5再之前的版本)
- 单件模式确保程序中一个类最多只有一个实例。
- 单件模式也提供访问这个实例的全局点。
- 单件模式需要私有的构造器,一个静态变量和一个静态方法。
- 确定在性能和资源的限制条件下,小心选择单件模式以解决多线程问题。
网友评论