[导读]
单例模式,顾名思义,只有一个实例。很多应用场景下,一个服务,一个组件都会以单例来运行。具体到一个类,一个类只能创建一个对象。
[正文]
1. 单例模式特征
(1). 外界不能显示创建对象,所以构造函数必须为private;
(2). 给外界提供唯一的访问实例的接口,一般名字为:getInstance(), 返回唯一的对象实例;
故单例类的类图可以表示为:
2. 模式实现
模式实现这一块内容相当丰富,尤其是在<<effective java>>里讨论得很精彩。按理说没有必要在这里累赘,就当烂笔头吧。
【实现1】
class Singleton {
private static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
【分析】上述实现为非线程安全,即在多线程环境下,可能产生多个实例,违背了单例的概念语义。
【实现2】
class Singleton {
private static Singleton instance = null;
private Singleton(){
}
public synchronized static Singleton getInstance() { // 比上面多了一个synchronized关键字
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
【分析】上述实现加了一个类级锁,能保证只创建一个实例,但每次取得实例意味着加锁一次,是否有效率提升的空间呢?
【实现3】
class Singleton {
private static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
【分析】上述实现就是最经典的double-check locking实现,在多线程环境里不是每个线程都会进入到synchronized同步模块。对于每一个线程,要获取实例都需要做第一层的if判断,依然是效率的问题。当然对比【实现2】,效率已经有了提升。
【实现4】
class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){
}
public static Singleton getInstance() {
return instance;
}
}
【分析】上述实现能直接获取单例实例,不用加锁,也不用做任何判断,效率达到了最佳。但是java的静态变量是不管你用不用,只要进程启动,静态变量都会初始化。能优化吗?
【实现5】
class Singleton {
private Singleton(){
}
public static Singleton getInstance() {
return SingletonMaker.instance;
}
private static class SingletonMaker{
public static Singleton instance = new Singleton();
}
}
【分析】增加一个私有静态内部类
(1).静态类不是变量, 所以SingletonMaker类里的成员不会在一开始就初始化
(2). 内部静态类,对外不可见。对内和Singleton是相互可见的。因此由它来创建单例实例,既能满足效率问题,又能避免资源集中在初始阶段去初始化。
这也是lazy load的实现。
ok了。最后一种当然也是最佳实现方式。