返回信息流个人看法:
问题在于synchronized(Singleton.class), 意思是同一时刻,只有一个线程能够执行同步块中的语句,也就是new 一个Singleton对象。 但是并不排斥其他线程使用这个instance。正如lz所说如果步骤3先发生于2,线程二有可能判断instance非空而使用没有初始化完的instance。
这是一条镜像帖。来源:北邮人论坛 / java / #52548同步于 2016/8/24
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
Re: 单例模式的双检锁实现为什么要加volatile
guanzhe
2016/8/24镜像同步10 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
初始化2次不会 但是有可能未完成初始化的时候,第二个线程在外层的if判断后得到not null 然后直接使用了
【 在 dss886 的大作中提到: 】
: 我觉得你的一二三讲得挺清楚的啊。。。
: instance 不为空的时候第一个线程还不一定完成了初始化,第二个线程有可能会进到if语句里面来,后果就是初始化了两次
= =! 对
【 在 Lamperouge 的大作中提到: 】
: 初始化2次不会 但是有可能未完成初始化的时候,第二个线程在外层的if判断后得到not null 然后直接使用了
https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
Intuitively, this algorithm seems like an efficient solution to the problem. However, this technique has many subtle problems and should usually be avoided. For example, consider the following sequence of events:
Thread A notices that the value is not initialized, so it obtains the lock and begins to initialize the value.
Due to the semantics of some programming languages, the code generated by the compiler is allowed to update the shared variable to point to a partially constructed object before A has finished performing the initialization. For example, in Java if a call to a constructor has been inlined then the shared variable may immediately be updated once the storage has been allocated but before the inlined constructor initializes the object.[5]
Thread B notices that the shared variable has been initialized (or so it appears), and returns its value. Because thread B believes the value is already initialized, it does not acquire the lock. If B uses the object before all of the initialization done by A is seen by B (either because A has not finished initializing it or because some of the initialized values in the object have not yet percolated to the memory B uses (cache coherence)), the program will likely crash.
One of the dangers of using double-checked locking in J2SE 1.4 (and earlier versions) is that it will often appear to work: it is not easy to distinguish between a correct implementation of the technique and one that has subtle problems. Depending on the compiler, the interleaving of threads by the scheduler and the nature of other concurrent system activity, failures resulting from an incorrect implementation of double-checked locking may only occur intermittently. Reproducing the failures can be difficult.
As of J2SE 5.0, this problem has been fixed. The volatile keyword now ensures that multiple threads handle the singleton instance correctly. This new idiom is described in [2] and [3].
噢,懂了 线程2可以访问instance,不用进入同步代码块
【 在 guanzhe 的大作中提到: 】
: 个人看法:
: 问题在于synchronized(Singleton.class), 意思是同一时刻,只有一个线程能够执行同步块中的语句,也就是new 一个Singleton对象。 但是并不排斥其他线程使用这个instance。正如lz所说如果步骤3先发生于2,线程二有可能判断instance非空而使用没有初始化完的instance。
六楼解释了这个问题。大致意思是:多个线程同时写内存,一个线程往多个不同内存空间里写入的顺序,在另一个线程看来可能是不一样的。所以,另一个线程有可能看到“对象的地址已经非null了,但里面的内容还没有写上”。volatile可以避免这种情况。
https://bbs.byr.cn/#!article/Java/39220
https://bbs.byr.cn/#!article/Java/48368