chapter 5 --单件模式
独一无二的对象
1. 如果我们不需要这个实例,它就永远不会产生,这就是“延迟实例化”。
2. 单件常被用来管理共享的资源,例如数据库连接或线程池。
3. 外界必须“请求”得到一个实例,而不是自行实例化得到一个实例。
单件模式:
确保一个类只有一个实例,并提供一个全局访问点
Structure
这个uniqueInstance类变量持有唯一的单件实例。getInstance()方法是静态的,这意味着它是一个类方法,所以可以在代码的任何地方使用Singleton.getInstance()访问它。这和访问全局变量一样简单,只是多了一个优点:单件可以延迟实例化。单件模式的类也可以是一般的类,具有一般的数据和方法。
Singleton模式的代码:
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
通过增加synchronized关键字到getInstance()方法中,我们迫使每个进程在进入这个方法之前,要先等候别的线程离开该方法。即不会有两个线程可以同时进入这个方法。
但是,只有第一次执行此方法时,才真正需要同步。一旦设置好uniqueInstance变量,实际上就不再需要同步这个方法了。之后的每次调用,同步都是一种累赘。可从使用以下来改善多线程的性能:
- 如果getInstance()的性能对应用程序不是很关键,就什么都别做。
- 使用“急切”创建实例,而不用延迟实例化的做法。
- 用“双重检查加锁”,在getInstance()中减少使用同步。
双重检查加锁代码:
public class Singleton {
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变量。
本章小结:
- 单件模式确保程序中一个类最多只有一个实例。
- 单件模式也提供访问这个实例的全局点。
- 在Java中实现单件模式需要私有的构造器、一个静态方法和一个静态变量。
- 确定在性能和资源上的限制,然后小心地选择适当的方案来实现单件,已解决多线程的问题。
- 如果不是采用第五版的Java 2,双重检查加锁实现会失效。
- 如果你使用多个类加载器,可能会导致单件失效而产生多个实例。
- 如果使用JVM 1.2或之前的版本,你必须建立单件注册表,以免垃圾收集器将单件回收。