介绍
单例模式确保一个类只有一个实例,并提供了一个全局访问点。
应用
线程池,数据库连接对象。
经典单例模式
一个经典的单例模式实现:
// NOTE: This is not thread safe! |
该实现是线程不安全的。可以想象有两个线程同时进入了getInstance()方法。
解决经典单例模式线程安全问题
解决方案,给getInstance方法加上synchronized关键字,迫使每个线程进入该方法前都需要等待别的线程离开该方法。
public class Singleton { |
该解决方案得缺点就是只有第一次执行该方法才真正需要线程同步。
更进一步…
这里给出三种改善方案:
- 如果getInstance得性能对于应用程序不是很关键,就什么也别做。
- 使用“急切”创建实例,而不用延迟实例化的做法。
public class Singleton { |
- 使用双重检查加锁,在getInstance中减少使用同步。
public class Singleton { |
备注:
- 首先检查实例是否存在,如果不存在再进入同步代码块。
- 进入区块后在检查一次,如果仍然是null则创建实例。
- volatile关键字确保:当instance变量初始化后,多个线程正确的处理instance变量。
思考
两个类加载器可能有机会创建自己的单例实例?
是的。所以如果你的程序有多个类加载器又同时使用了单例模式,请小心。解决方法是自行指定类加载器,并指定同一个类加载器。
类如果能做两件事,就违反了OO设计。单例模式是否违反了这样的观念呢?
单例类不止负责管理自己的实例,还在应用程序中担任角色,所以可以视为是两个责任。但是由类管理自己的实例的做法并不少见,也可以让设计更简单。
我想把单例类当成超类,设计出子类。究竟可不可以继承单例类。
不能。继承单例类遇到的一个问题就是构造器是私有的。你不能用私有构造器来扩展类。
参考资料
- 《Head First设计模式》(中文版)