关于双重检查成例的问题

zhakeer 2006-04-11 12:38:43
已经知道,对于java单例模式,如下的代码
if(instance==null){
synchronized(Singleton.class){
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
是不成立或者说是不安全的,但是为什么
if(instance==null){
synchronized(Singleton.class){
if(instance==null){
Singleton tmp=new Singleton();
instance=tmp;
}
}
}
return instance;
也不行呢?
...全文
280 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhakeer 2006-04-14
  • 打赏
  • 举报
回复
首先感谢各位的答复,但是你们的回答并不能解决我的疑惑,还请达人们给出正确的答案
gogon 2006-04-13
  • 打赏
  • 举报
回复
DCL 在1.4或者以前的版本里是不成立的.因为那时jvm的实现里,对于代码 MyClass mine=new MyClass()执行时,在完成new MyClass()的初始化前,就先将mine 赋予了指向即将创造的那个对象的地址.这样就可能导致调用尚未初始化的对象而导致的不可预期错误.
不过如果你使用的5.0的话,就不用担心了.这个错误已经被纠正了
水晶平衡木 2006-04-12
  • 打赏
  • 举报
回复
嗯,我认为后者没有什么不行的(除非instance=tmp;操作不是原子的,中间还可能生出什么异端来,^_^),支持一下。
zhakeer 2006-04-11
  • 打赏
  • 举报
回复
to classjava(原始野人) ( ) 信誉:105
如果仅仅是你说的3个前提
Singleton tmp=new Singleton();
instance=tmp;
就已经可以避免这种情况,但为什么还是说双重检查成例是不成立的呢?
classjava 2006-04-11
  • 打赏
  • 举报
回复

前提1:Java 使得它的每个线程使用独立的处理器和一个私有的内存空间,每一个线程的私有内存都会与主存交互与同步。synchronized 块会建立一个内存壁垒(memory barrier) ,当进入synchronized块时会建立一个read barrier :它会使得Thread的本地内存无效,并且从主存中读取所有的变量的值。当退出一个synchronized块时,它会确保将对所有本地内存的改变都同步到主存中。并且synchronized也会保证这段代码是原子操作。
前提2:假设一个new操作需要以下两个步骤(也许更多)1.分配相应内存2.调用构造函数。
前提3:我们不能在书写我们的代码时预计指令真正的执行顺序,他可能由于编译器,处理器和缓存机制的干预而变化。规范规定:编译器编译器,处理器和缓存机制可以任意改变指令顺序,只要不影响结果的值。
实例
public Resource getResource(){
if (resource == null){ // a:
synchronized(this){
if (resource==null){
resource = new Resource(); //b:
}
}
}return resource;//c
}

解释
有了以上的前提,我们可以讨论DCL是如何导致线程不安全的。假设:一个线程t1进入getResource()方法,并且执行到b处。这时另一个线程t2进入。当它在a处时t1刚好进行完分配内存的工作,而没有调用构造函数。这时T2会认为resource不为null因而直接来到c处,得到了一个错误的resource实例。显而易见会导致错误。
classjava 2006-04-11
  • 打赏
  • 举报
回复
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
zhakeer 2006-04-11
  • 打赏
  • 举报
回复
to icy_csdn() ( ) 信誉:110

你说的问题我是知道的,我问的是为什么
synchronized(Singleton.class){
if(instance==null){
Singleton tmp=new Singleton();
instance=tmp;
}
}
也不行
icy_csdn 2006-04-11
  • 打赏
  • 举报
回复
// Singleton instance
private static Singleton instance = null;

public static Singleton getInstance(){
/*
* 双重检验模式,内嵌同步机制。这里是第一重检验。
*/
if (instance == null) {
/*
* 同一时刻只有一个线程进入。
*/
synchronized (SSOTokenManager.class) {
/*
* 如果第二个线程在这里等待,它将发现instance已经被初始化,
* 因此不再会重新初始化instance变量,这就是双重检验。
*/

if (instance == null) {
/*
* 这里是关键,lazy实例化singleton变量。
*/
instance = new Singleton();
}
}
}
return (instance);
}
icy_csdn 2006-04-11
  • 打赏
  • 举报
回复
// Singleton instance
private static Singleton instance = null;

public static Singleton getInstance(){
/*
* 双重检验模式,内嵌同步机制。这里是第一重检验。
*/
if (instance == null) {
/*
* 同一时刻只有一个线程进入。
*/
synchronized (Singleton.class) {
/*
* 如果第二个线程在这里等待,它将发现instance已经被初始化,
* 因此不再会重新初始化instance变量,这就是双重检验。
*/

if (instance == null) {
/*
* 这里是关键,lazy实例化singleton变量。
*/
instance = new Singleton();
}
}
}
return (instance);
}

50,526

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧