zoukankan      html  css  js  c++  java
  • 设计模式——单例模式

    单例模式

    传统的写法

    /**
    * 懒汉模式
    */
    public class Singleton {
        private static Singleton instance = null;
    
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    
    /**
     * 饿汉模式
     */
    class SingletonWithHungry {
        private SingletonWithHungry() {
        }
    
        private SingletonWithHungry instance = new SingletonWithHungry();
    
        public SingletonWithHungry getInstance() {
            return instance;
        }
    }
    
    /**
    * 枚举单例
    */
    public enum Girlfriend{
    	GIRLFRIEND;
    }
    
    
    /**
    * 静态内部类
    */
    public class SingleTon{
      private SingleTon(){}
     
      private static class SingleTonHoler{
         private static SingleTon INSTANCE = new SingleTon();
     }
     
      public static SingleTon getInstance(){
        return SingleTonHoler.INSTANCE;
      }
    }
    
    

    懒汉模式的线程不安全复现

    class TestSingleWithThread {
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread(() -> {
                System.err.println(Singleton.getInstance());
            });
            Thread t2 = new Thread(() -> {
                System.err.println(Singleton.getInstance());
            });
            t1.start();
            t2.start();
            t1.join();
            t2.join();
        }
    }
    

    解决方案:

    1. 懒人同步——getInstance方法加上synchronized关键字
    2. DCL——Double Checked Lock双重检查锁定

    DCL:

    class SingletonThreadSafeDCL {
        private static SingletonThreadSafeDCL instance = null;
    
        private SingletonThreadSafeDCL() {
        }
    
        public static SingletonThreadSafeDCL getInstance() {
            if (instance == null) {//(1)
                synchronized (SingletonThreadSafeDCL.class) {//(2)
                    if (instance == null) {//(3)
                        instance = new SingletonThreadSafeDCL();//(4)
                    }
                }
            }
            return instance;
        }
    }
    

    关于DCL存在的问题,参考《并发编程的艺术》3.8节。

    线程执行到(1)时,代码读取到的instance不为null,instance引用的对象可能还没完成初始化

    而new SingletonThreadSafeDCL()在JVM中分为三步:

      1.在堆内存开辟内存空间。
      2.在堆内存中实例化SingleTon里面的各个参数。
      3.把对象指向堆内存空间。
    

    由于重排序,可能导致3在2之前执行,

    因此,导致线程B访问到了一个未初始化的对象。

    比如单例有属性name,在新建实例时name 初始化为Michael,线程B访问到instance时,name未完成初始化,两个线程读到的值不一致。

    解决DCL

    1. volatile,禁止重排序

    扩展: volatile happens-before, volatile JMM语义

    1. 基于类初始化的解决方案
    当你准备好了,机会来临的时候,你才能抓住
  • 相关阅读:
    数据库用户管理
    数据库(视图,事件,触发器,函数,存储,变量)
    我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3cp8ng15g94wc
    Python3安装与使用urllib2包之小坑
    移动端的vw px rem之间换算
    H5移动端开发
    实现拖拽复制和可排序的react.js组件
    vue2实现搜索结果中的搜索关键字高亮
    来,了解一下Java内存模型(JMM)
    video标签学习使用
  • 原文地址:https://www.cnblogs.com/studentytj/p/11541454.html
Copyright © 2011-2022 走看看