当前位置 博文首页 > 文章内容

    双重检查锁定在Java中的陷阱 java设计模式后端性能优化

    作者:929794951 栏目:IT热点 时间:2020-06-04 9:32:45

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



         双重检查锁定(也叫做双重检查锁定优化)是一种软件设计模式。

         它的作用是减少延迟初始化在多线程环境下获取锁的次数,尤其是单例模式下比较突出。

         软件设计模式:解决常用问题的通用解决方案。编程中针对一些常见业务固有的模版。

         延迟初始化:在编程中,将对象的创建,值计算或其他昂贵过程延迟到第一次使用时进行。

         单例模式:在一定范围内,只生成一个实例对象。

    Java中的双重检查锁定

         单例模式我们需保证实例只初始化一次。

         下面例子在单线程环境奏效,多线程环境下会有线程安全问题(instance被初始化多次)。

         下面例子主要是性能问题。首先加锁操作开销很大,因为线程安全发生在对象初始化,而这里做了做了全局控制,造成浪费。

         为了控制线程安全又能保证性能,双重检查锁定模式出现。

         逻辑如下


         我们分析一下执行逻辑

         假设有三个线程 T1 T2 T3 ,依次访问 getInstance 方法。

    1. T1 第一次检查为Null 进入同步块,T1持有锁,第二次检查为Null 执行对象创建。

    2. T2 第一次检查为Null 进入同步块,T2等待T1释放锁,锁释放后,T2进入执行第二次检查不为Null,返回实例对象。

    3. T3 第一次检查不为Null,直接返回对象。


         上面一切似乎很完美,但是这里面存在陷阱。根据Java内存模型我们知道,编译器优化处理会进行重排序。

         instance = new Singleton() 大体分两个步骤;

         1 创建初始化对象;

         2 引用赋值。

         而 1 2 步骤可能颠倒,会造成对象属性在初始化前调用的错误。

         这种细微的错误不容易出现,但是它的确存在。大家可以参考下面这份报告,里面详细记录这个问题。

         1 利用 ThreadLocal

         2 利用volatile(解决重排序问题)


         本章节主要记录了双重检查锁定模式使用中应该注意的细微事项。

         欢迎大家留言交流,一起学习分享!!!

         

         原文链接:https://segmentfault.com/a/1190000022806313

         如有侵权,请联系删除。