为什么singleton双重检查成例对Java 语言编译器不成立?

AprilChen 2003-09-16 11:44:14
public class LazySingleton
{
private static LazySingleton m_instance = null;
private LazySingleton() { }
/**
* 静态工厂方法
*/
public static LazySingleton getInstance()
{
if (m_instance == null)
{
//More than one threads might be here!!!
synchronized(LazySingleton.class)
{
if (m_instance == null)
{
m_instance = new LazySingleton();
}
}
}
return m_instance;
}
}

java与模式中解释到:在Java 编译器中,LazySingleton 类的初始化与m_instance 变量赋值的顺序不可预料。如果一个线程在没有同步化的条件下读取m_instance 引用,并调用这个对象的方法的话,可能会发现对象的初始化过程尚未完成,从而造成崩溃。

第二句不理解!请指点!
...全文
149 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
q_starry 2003-09-29
  • 打赏
  • 举报
回复
to jeffyan77(jeffyan77)
十分感谢,公开的章节我已经很过了,所以想找全本的看一下。
国内关于这方面的资料太少。为了找点资料就要花费很长的时间。
jeffyan77 2003-09-29
  • 打赏
  • 举报
回复
还有一本也不错,就是老了一点:

Programming for the Java Virtual Machine
By Joshua Engel

Publisher : Addison Wesley

中文版我不清楚。
jeffyan77 2003-09-29
  • 打赏
  • 举报
回复
如果你也看英文的话,我网站上有这本书的英文版(一部分):
http://www.webendshere.com/books/ebooklinks/index.htm
(Java类别里《Inside Java Virtual Machine》)。那儿还有一些别的书。
jeffyan77 2003-09-29
  • 打赏
  • 举报
回复
美国公司稍为大一点的,都有自己的图书馆,对员工开放。

国内公司也应当有自己的图书馆,毕竟比提供培训要省钱的多,何乐而不为呢
q_starry 2003-09-28
  • 打赏
  • 举报
回复
starry@263.net
msn q_debu@hotmail.com
q_starry 2003-09-28
  • 打赏
  • 举报
回复
to jeffyan77(jeffyan77)
谢谢,可惜。
to Schlemiel(维特根斯坦的扇子)
你在哪里?我在北京。可以的话能否借我?或者国内哪里可以买到?
如果你仔细看过,我想请教一下。万分感谢
Schlemiel 2003-09-28
  • 打赏
  • 举报
回复
没记错的话,我倒是有一本Inside JVM,Bill Venners著,蔡学镛译的繁体中文版。可惜,呵呵,没法给楼上的兄弟了。
jeffyan77 2003-09-28
  • 打赏
  • 举报
回复
To q_starry(秦):

抱歉,我不知道。那位知道的,告诉一声。

阎宏
www.WebEndsHere.com
Yanbin_Q 2003-09-27
  • 打赏
  • 举报
回复
我不去研究那么多,我也记住了在java中不成立就行了,出什么事俺可以依着阎博士,向他要说法去(倒是到哪里能找到他呢?),其余的我不管
q_starry 2003-09-27
  • 打赏
  • 举报
回复
to jeffyan77(jeffyan77)
请问国内哪里可以查到《Inside JVM》这本书?
UpbeatJackson 2003-09-27
  • 打赏
  • 举报
回复

谁是阎博士,他写了什么书?
Cowboy22 2003-09-25
  • 打赏
  • 举报
回复
c++优化指令的做法是把常用的数据放到CUP的内部寄存器中, 多线程程序中一旦另外一个线程修改了这个变量, 那么这个变量在寄存器中就过期了. c/c++的volatile就是用来防止这个优化的"负作用".
captiveRobotCN 2003-09-25
  • 打赏
  • 举报
回复
to AprilChen (babysky) :
你仔细读一下:java与模式中解释到:在Java 编译器中,LazySingleton 类的初始化与m_instance 变量赋值的顺序不可预料。如果一个线程在没有同步化的条件下读取m_instance 引用,并调用这个对象的方法的话,可能会发现对象的初始化过程尚未完成,从而造成崩溃。
我的解释如下:
!!!(并调用这个对象的方法的话,可能会发现对象的初始化过程尚未完成,从而造成崩溃。)
他的意思是说:m_instance已经赋值,但是LazySingleton初始化未完成。
new m_instance()只是给他分配一块内存。单线程当然没问题。
你想想多线程的情况肯定就有问题了!
是不是?
Cowboy22 2003-09-23
  • 打赏
  • 举报
回复
C++规范规定对象构造的动作次序由类的声明顺序决定的, 要写一个线程安全的Singleton大概可以这样写:
tempalte<typename T>
class Singleton
{
private:
  static T* m_instance;
  Singleton()
  {}
public:
  static T* Instance()
  {
    if(instance==NULL)
    {
      lock();
if(!m_instance)
      m_instance = new T();
      unlock();
    }
    return m_instance;
  }
};

ajoo 2003-09-23
  • 打赏
  • 举报
回复
为什么?难道c++不允许优化更改指令的执行顺序吗?

cowboy22, java的double check也不是因为对象构造的顺序造成的。
jeffyan77 2003-09-23
  • 打赏
  • 举报
回复
这个问题只存在于Java语言中,C++, C#, VB6.0, VB.NET, Delphi等均无问题。
Schlemiel 2003-09-22
  • 打赏
  • 举报
回复
to ajoo(聪明的一猪):
C++下Double-Checked Locking是安全的,C++规范规定了对象构造的动作次序(如果我没记错的话)。
Kidwish 2003-09-22
  • 打赏
  • 举报
回复
public class LazySingleton
{
private static boolean initialized = false;
private static LazySingleton m_instance = null;
private LazySingleton() { }
/**
* 静态工厂方法
*/
public static LazySingleton getInstance()
{
if (!initialized)
{
//More than one threads might be here!!!
synchronized(LazySingleton.class)
{
if (m_instance==null)
{
m_instance = new LazySingleton();
initialized = true;
}
}
}
return m_instance;
}
}
AprilChen 2003-09-19
  • 打赏
  • 举报
回复
craks() :你这样做回带来很大的性能问题!
ajoo 2003-09-18
  • 打赏
  • 举报
回复
假设构造函数如下:
LazySingleton(){this.i=0;}

那么,这个
m_instance = new LazySingleton();
initialized = true;
的运行时操作可以被扩展成:

分配内存;
调用构造函数,把i初始化成0
m_instance = 这个内存的指针
initialized = true;


看着好像没问题,是吗?因为当initialized被置的时候,内存应该已经分配好了,也初始化好了。

如果把上面的四行看成一个黑盒,那么,当这四句执行完毕之后,它的效果就是initialized为true, m_instance指向了一个初始化好的对象。
只要满足了这个效果,编译器不论如何搞都是可以的。

可是,所有这些都是从单线程来看的。java允许jvm在不影响单线程的执行语义的情况下,改变语句的执行顺序!

考虑把上面的语句改变一下顺序:
分配内存;
initialized = true;
m_instance = 这个内存的指针
调用构造函数,把i初始化成0
同样是个黑盒,执行后的结果和前面是一样的。所以,这也就是一个符合java标准的合法的优化的选择。

现在,再看看你的另外一个线程,还安全吗?

volatile变量是一个符合标准的解决方法,因为它禁止jvm更改对它的执行顺序。但是,好像据说不是所有jvm都符合这个标准的。:(
所以,保守地说,double check根本不能用。

其实,何必麻烦呢?直接就static final Singleton = new Singleton();
多爽?

一个让我好奇的是,不知道c++下,double check是否安全。哪位知道c++的标准的?
加载更多回复(10)

51,407

社区成员

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

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