先上代码:
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null)
instance = new Singleton();
}
}
return instance;
}```
#分析:
- 线程1进入方法体,满足条件instance == null,进入synchronized块
- 线程间抢占cpu资源,线程1被线程2预占,线程2进入方法体
- 此时方法还没执行完,对象还没有创建出来instance依然为null
- 线程2试图获取锁资源,但线程1持有该锁,于是线程2阻塞,线程2被线程1预占
- 线程1继续执行,此时instance 仍然为null,创建Singleton实例并将其引用赋值给instance,方法返回该实例对象的引用,退出方法
- 线程1被线程2预占,线程2获取锁并检查 instance是否为 null.由于instance 已经被赋值,所以不会创建第二个 Singleton 对象.
这样一套双重检查加锁机制实现了比普通单例模式更高效率的逻辑
###但是该双重检查加锁机制也有不完美之处:
双重检查锁定并不能保证它会在单处理器或多处理器计算机上顺利运行。 双重检查锁定失败的问题并不归咎于JVM中的实现 bug,而是归咎于 Java 平台内存模型.内存模型允许所谓的“无序写入”,这也是这些习语失败的一个主要原因.
###最终采用以下代码,才弥补了双重检查加锁的机制的缺陷:
``` public static Singleton getInstance(){
if (instance == null) {
synchronized(Singleton.class) {
Singleton inst = instance;
if (inst == null) {
synchronized(Singleton.class) {
instance = new Singleton();
}
}
}
}
return instance;
}```
####用 volatile 声明每一个变量怎么样?
另一个想法是针对变量 inst以及 instance使用关键字 volatile,根据 JLS(参见 参考资料),声明成 volatile的变量被认为是顺序一致的,即,不是重新排序的。但是试图使用 volatile来修正双重检查锁定的问题,会产生以下两个问题:
这里的问题不是有关顺序一致性的,而是代码被移动了,不是重新排序。
即使考虑了顺序一致性,大多数的 JVM 也没有正确地实现 volatile
网友评论