zoukankan      html  css  js  c++  java
  • DCL的单例一定是线程安全的吗

    读了本文,你会知道,为什么不加volatile关键字的单例模式不是线程安全的

    有经验的开发者都知道双重锁定检查(DCL,Double Check Lock)的单例是最优秀的,如下文所示:

     1 public class Singleton {
     2     private static Singleton instance = null;
     3     public  static Singleton getInstance() {
     4         if(null == instance) {    // 第一次检查
     5             synchronized (Singleton.class) {
     6                 if(null == instance) {   // 加锁后第二次检查                 
     7                     instance = new Singleton();    
     8                 }
     9             }
    10         }
    11        
    12         return instance; 
    13         
    14     }
    15 }

    这看上去一切都很完美,无懈可击,但实际上这个 getInstance() 方法并不完美。问题出在哪里呢?出在 new 操作上,我们以为的 new 操作应该是:

    1. 分配一块内存 M;
    2. 在内存 M 上初始化 Singleton 对象;
    3. 然后 M 的地址赋值给 instance 变量。

    但是实际上,经过编译器优化后的执行顺序是这样的:

    1. 分配一块内存 M;
    2. 将 M 的地址赋值给 instance 变量;
    3. 最后在内存 M 上初始化 Singleton 对象。

    如下图所示,线程A进入<第一次检查>,A先获得Synchronize锁,分配一块内存M,先将M的地址赋值给了 instance 变量, 此刻发生线程切换,线程B检测到instance不为空,直接返回未初始化的instance, 如果我们这个时候访问 instance 的成员变量就可能触发空指针异常。    

    所以,我们会加对象上加 Volatile关键字,禁止指令重排序,

    Volatile的原理,可以参考我的另一篇文章:Java多线程的volatile底层实现原理

    ==========================================================================           如果您觉得这篇文章对你有帮助,可以【关注我】或者【点赞】,希望我们一起在架构的路上,并肩齐行
    ==========================================================================
  • 相关阅读:
    SpringBoot项目中,表单的验证操作
    微信点餐系统(十)-卖家端通用功能和上下架
    IDEA中Springboot静态文件加载(热部署)
    微信点餐系统(九)-卖家端订单
    微信点餐系统(八)-微信支付与退款
    MyBatis的生命周期
    关于flexjson将json转为javabean的使用
    Spring MVC中前端控制器拦截问题
    springmvc实现文件上传
    springmvc拦截器实现用户登录权限验证
  • 原文地址:https://www.cnblogs.com/amberJava/p/12546798.html
Copyright © 2011-2022 走看看