论坛首页 Java企业应用论坛

关于单例模式的DoubleCheckLock同步的思考

浏览 6808 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-12-25   最后修改:2010-12-25
其实我关心的是:有没有朋友在实际的项目开发中,使用了最简单、理论上性能最低的方法级同步锁来延迟获取单例,也就是第一种方案,后来经过了实际profiling测试,方法级同步锁确实造成了实际的性能瓶颈,改为DoubleCheck方式后,性能获得了实质提升的经验?

因为我平时接触JEE的应用比较多,而在很多JEE的应用或框架中,也比较少见使用DoubleCheck来做单例的,当然可能是JDK1.4的DoubleCheck的bug导致了这样的现状,但事实上也没有实际看到方法级同步锁单例造成性能瓶颈的情况,才引发了我上面的思考。或者在纯J2SE编程中有这样的场景?想听听各位朋友的看法。
0 请登录后投票
   发表时间:2010-12-25   最后修改:2010-12-25
一个可能性比较大的原因是,在代码内部直接使用静态类方法来获取对象实例会导致该段代码难以进行单元测试。(因为无法注入通过静态类方法来获取到的对象的mock)

因此在使用了单元测试的项目中,我们倾向于仅仅在某些粗粒度的阶段的起始位置(例如servlet的初始化阶段,或者刚刚开始处理请求时)用单例上的静态类方法来获取实例,之后会将这个实例作为方法参数传递下去,或者放入这个阶段的线程独立的上下文中,在后续的代码中直接通过上下文提取。

这样一来,本来在系统中直接调用静态方法来获取单例的机会就不多,而同步体内部的内容执行速度又快,仅仅是返回结果而已,刚好同时命中争夺资源的情况就少之又少了。强并发数在大到会在单例的getInstance方法上发生严重同步阻塞之前,早就在其他地方出现了严重的性能瓶颈了。
0 请登录后投票
   发表时间:2010-12-25  
DoubleCheck翻译成双锁?还真是会发明名词。
Java内存模型允许写入无序?N年前的东西还拿出来,写程序的都成考古的了。
如果还有遗留的JVM上存在所谓写入无序的bug,完全可以用简单的方式解决。
无论如何,对单例模式来说,DoubleCheck是个比较理想的方式。在高并发的情况下,同步锁竞争的开销是非常巨大的,况且单例是一次写,多次读。
Object instance = null;
Object getInstance()
{
    if(instance==null)
    {
        synchronized(thisOrClass)
        {
           if(instance == null)
           {
               instance = createInstance();
           }
        }
    }
}
/*
不直接使用new,即使局部存在写入无序的bug,也不会影响到返回结果
支持inline的JVM都比较新,没有这样的bug。
*/
Object createInstance()
{
    return new ...;
}
0 请登录后投票
   发表时间:2010-12-25   最后修改:2010-12-25
楼上关于翻译的问题说得好,但"双重检查同步锁"又太长,已经统一更正为DoubleCheckLock。谢谢指出。

DoubleCheckLock的理论性能比方法同步锁快是肯定的,在很多非静态方法中进行延迟实例化,我也喜欢用DoubleCheckLock。这里讨论的是在单例这种特殊场景下,性能差别是否关键的。毕竟在写程序时,我们不希望关注太多业务无关的概念,除非真的有必要。
0 请登录后投票
   发表时间:2010-12-25  
关于是不是性能瓶颈,有没有必要优化的问题,应该是针对比较复杂或有副作用的方式方法,简单有效的好方法,还是能用尽量用。
我们在这里讨论的都是业务无关的东西,写程序、做设计不重视细节的话,永远做不出好产品。
0 请登录后投票
论坛首页 Java企业应用版

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