论坛首页 综合技术论坛

有必要普及一下关于单例模式的常识.

浏览 20025 次
精华帖 (2) :: 良好帖 (10) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-03-26  
不错,分析的很到位~
0 请登录后投票
   发表时间:2012-03-26  
mlc880926 写道
多个JVM的情况也讲解下啊

多个虚拟机这样的情况就使用类似分步缓存这样的实现方式就可以了嘛,只要保证所有的虚拟机都从同一接口获取资源就可以了。
0 请登录后投票
   发表时间:2012-03-27  
池中物 写道
private static volatile DoubleCheckLockSingleton instance = null;  

有了volatile,  double-check是可以的


这个根本就不是有没有volatile,因为在同步块中,数据都会从寄存器中被刷到内存中。
0 请登录后投票
   发表时间:2012-03-27  
好象懒汉式和双重检验锁都不主张使用,除非保证程序只在单线程下运行。 枚举单例好象最安全。
0 请登录后投票
   发表时间:2012-03-27  
phk070832 写道
池中物 写道
private static volatile DoubleCheckLockSingleton instance = null;  

有了volatile,  double-check是可以的


这个根本就不是有没有volatile,因为在同步块中,数据都会从寄存器中被刷到内存中。


难道double-check 写法在多线程下是错误的?
我觉的加volatile是没错
volatile保证了内存可见性
0 请登录后投票
   发表时间:2012-03-27  
spyker 写道
phk070832 写道
池中物 写道
private static volatile DoubleCheckLockSingleton instance = null;  

有了volatile,  double-check是可以的


这个根本就不是有没有volatile,因为在同步块中,数据都会从寄存器中被刷到内存中。


难道double-check 写法在多线程下是错误的?
我觉的加volatile是没错
volatile保证了内存可见性


这个不是加volatile有错,而是加不加volatile是一件无所谓的事情


   if(instance == null){    // first check 
     synchronized(DoubleCheckLockSingleton.class){  // 因为这里已经有个synchronized,数据会被刷新到内存中
      if(instance == null){  //second check 
         instance =new DoubleCheckLockSingleton(); 
         } 
       } 
     } 
0 请登录后投票
   发表时间:2012-03-27  
这个跟《研磨设计模式》上讲的单例模式很像,不过讲得不错,浅显明白
0 请登录后投票
   发表时间:2012-03-27  
spyker 写道
以后写单例  尽量用enum写吧
貌似 争议最小 安全性最高



effective java推荐使用枚举的单例模式
0 请登录后投票
   发表时间:2012-03-28   最后修改:2012-03-28
每次看到双重锁初始化实例,都有种想吐的感觉:

"在很早的以前的JVM中,同步,甚至是无竞争的同步,都存在惊人的开销。结果是很多聪明的(至少看上去聪明的)的小技巧被发明出来----有的好、有的坏、有的丑----以降低同步的影响。双重锁属于丑的那类"

"通过双重锁,线程可能看到引用的当前值,但是对象的状态值却是过期的"(要加volatile)

"无论如何,双重锁这个技巧的使用已经被广泛地废弃了----催生它的动力(缓慢无竞争的同步和缓慢的JVM启动)已经不复存在"

"惰性初始化容器提供了同样的好处,而且更容易理解"
0 请登录后投票
   发表时间:2012-03-28   最后修改:2012-03-28
phk070832 写道
spyker 写道
phk070832 写道
池中物 写道
。。。


这个根本就不是有没有volatile,因为在同步块中,数据都会从寄存器中被刷到内存中。


。。。


这个不是加volatile有错,而是加不加volatile是一件无所谓的事情


   if(instance == null){    // first check 
     synchronized(DoubleCheckLockSingleton.class){  // 因为这里已经有个synchronized,数据会被刷新到内存中
      if(instance == null){  //second check 
         instance =new DoubleCheckLockSingleton(); 
         } 
       } 
     } 



我都怀疑你是否知道double-check存在bug的原因在哪里?


if(instance == null){    // a
     synchronized(DoubleCheckLockSingleton.class){ 
      if(instance == null){  //second check 
         instance =new DoubleCheckLockSingleton(); // b 
         } 
       } 
     } 

这段代码的问题在于2个线程分别在a,b行时,可能存在b行位置的执行还没完成,a行判断已经不为null了。

产生这个情况的根本原因是指令重排,一些编译器会做指令重排优化,即使编译器不做,CPU为了流水线指令的最优执行也会做指令重排,称为乱序执行(out-of-order)。
假设 instance = new DoubleCheckLockSingleton() 的执行可简单分为3步
1.分配内存
2.执行构造函数
3.给instance赋值。
但是在编译器或cpu看来,第3步是可能在第2步之前执行的(因为不影响结果),如果这样就可能出现对象构造函数还没完成,a行判断已经不为null的情况,这个时候对返回instance的调用当然就会出现问题。

如果给instance加上volatile关键字就不一样了,volatile关键字最终会在访问该变量的时候加上内存障碍指令(barrier()),就是在内存障碍指令后的代码一定不会在前面执行,这样保证了顺序不会打乱。
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics