zoukankan      html  css  js  c++  java
  • 单例模式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

  • 相关阅读:
    Java实现 LeetCode 242 有效的字母异位词
    Java实现 LeetCode 212 单词搜索 II
    Java实现 LeetCode 212 单词搜索 II
    Java实现 LeetCode 212 单词搜索 II
    Java实现 LeetCode 212 单词搜索 II
    Java实现 LeetCode 344 反转字符串
    Java实现 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
    Java实现 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
    Java实现 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
    Java实现 洛谷 P1208 [USACO1.3]混合牛奶 Mixing Milk
  • 原文地址:https://www.cnblogs.com/ttaall/p/14208592.html
Copyright © 2011-2022 走看看