• 单例模式double check的演进及原理


    单例单例,就是只允许实例化一个对象。一般实现方式也就是将构造方法私有化,然后对外暴露一个获取实例的接口

    单例 可以说源自于设计模式中的单例模式吧,多种实现演进,变得越来越靠谱

    最早单例模式分为懒汉式 饿汉式  

    懒汉式:

    懒汉式很简单啊,就是全局变量声明时候直接new了,但是这样会有个占用内存的问题,因为如果这个实例用不到,那不是白白浪费空间了,尤其是项目庞大寸土寸金的JVM内存空间

    懒汉式的有点也很明显,简单好用,而且不会有乱七八糟的线程安全问题,所以单例的这个实例一定会用到的话 用懒汉式直接实现也无妨

    饿汉式:

    最原始的饿汉式,外部获取实例的时候先判断 实例是不是null,如果空的直接new一个

    单线程的世界里这样搞绝对没问题,但是问题就出在了多线程的情况下,当多个线程同时调用getInstance() ,然后同时判断了singlon为null,也就会new两个实例出来,违反了单例。

    怎么办呢,为了多线程安全 那就加锁呗

    这下放心了,多线程来调用这个方法的时候,不许抢都得给我排队串行来执行,也就保证了只会new一次Singlon

    但是还有问题,synchronized 这么重量级的锁 直接加到了这个方法上是不是不太好啊,如果多个线程经常频繁的会调用这个方法,都串行执行那也太难受了 (即时jdk1.8 后synchronized会有锁升级)

    so 尽量轻量一点 只在if条件确定了singlon==null的时候 再加锁行不行?

    if(singlon == null){

      synchronized(this){

        singlon = new Singlon();

      }

    }

    不行啊,如果恰好就有两个同时判断了singlon == null 然后同时进入到了if的代码块,加锁并没有阻止第二个线程new Singlon啊

    应运而生了double-check    一次判断不够用 我再来一次被

    在锁里在判断一次 这下放心了吧

    以为到这万事大吉了,其实并不然.虽然这种情况发生的概率不大,指令重排序导致的多线程安全问题

    singlon = new Singlon();  这一行代码 在底层其实是三条指令完成的

    1.开辟一块堆内存空间 

    2. 初始化一个Singlon对象

    3. singlon声明指向这个对象

    由于指令重排,很有可能 2 3步进行重排,1 3 2 的顺序执行,

    但第一个线程执行完了1 3步,这个时候,第二个线程进入方法 判断了一下singlon不为null 就直接返回了,事实上这个 singlon表面上不为null 但是还没来得及实实在在的实例化,导致直接return出问题

    那咋办呢  加volatile 防止指令重排呗

    实现单例的方式还有很多  比如常用的静态内部类 静态代码块 或者更简单直接用枚举它不香吗? 这里就不一一列举了 over

  • 相关阅读:
    hbase单机安装和简单使用
    工作随记--div最小高度
    工作随记——弹出QQ联系方式
    关于vs2012解决方案中项目DLL文件引用问题
    工作随想——框架之我见
    jQuery 选择表格(table)里的行和列及改变简单样式
    ASP.NET的Get和Post方式的区别归纳总结
    C# 静态类与非静态类、静态成员的区别
    引用静态资源的url添加版本号,解决版本发布后的浏览器缓存有关问题
    python技巧 一等函数
  • 原文地址:https://www.cnblogs.com/ttaall/p/14208592.html
Copyright © 2020-2023  润新知