zoukankan      html  css  js  c++  java
  • DCL-单例模式的线程安全

    DCL-Double Check Lock

    双端检锁机制

    传统单机环境下的单例模式

    public class Test002 {
    
        private static Test002 instance = null;
    
        private Test002(){
            System.out.println(Thread.currentThread().getName() + "	这是一个构造器" );
        }
    
        public static Test002 getInstance(){
            if(instance == null){
                instance = new Test002();
            }
    
            return instance;
        }
    
        public static void main(String[] args) {
            System.out.println(Test002.getInstance() == Test002.getInstance());
            System.out.println(Test002.getInstance() == Test002.getInstance());
            System.out.println(Test002.getInstance() == Test002.getInstance());
        }
    }
    

    输出结果

    多线程环境下

    public static void main(String[] args) {
            for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                  Test002.getInstance();
                },String.valueOf(i)).start();
            }
        }
    

    输出结果

    解决方法

    传统可以加sync,但是sync是重锁,存在很大的弊端,直接把整个方法getInstance()加锁了
    所以我们采用DCL-双端检锁机制,只给代码块加sync

    public static Test002 getInstance(){
    
            if(instance == null){
                synchronized(Test002.class){
                    if(instance == null){
                        instance = new Test002();
                    }
                }
            }
            return instance;
        }
    

    但是这样会出现指令重排,高并发多线程环境下,底层会对指令进行优化,导致顺序发生改变,可能会出现问题
    原因是某一个线程执行到第一次检测时,读取到的instance不为null时,instance的引用对象可能还没有完成
    初始化(但是内存已经被分配出去了)

    instance = new Instance()可以分成以下三步:

    memory = allocate();// 1.分配对象内存空间
    instance(memory);// 2.初始化对象
    instance = memory;// 3.设置instance指向刚刚分配的内存地址,此时instance!=null;
    

    步骤2,3不存在数据依赖关系,所以可以进行重排优化
    因此,需要加volatile修饰

    private static volatile Test002 instance = null;
    
  • 相关阅读:
    ROS中.launch文件的remap标签详解
    宝宝刷 leetcode
    ROS rosrun 调用 sudo 命令
    在moveit编译时找不到manipulation_msgsConfig.cmake manipulation_msgs-config.cmake文件
    CMake error with move_base_msgs问题解决
    VIVE pro和hololens购买调研
    /usr/bin/ld: 找不到 -lmsc----解决方案
    ubuntu16.04安装kinetic调用gazebo_control解决方案
    tomcat http协议与ajp协议
    GC日志分析
  • 原文地址:https://www.cnblogs.com/zhangyuanbo/p/14188532.html
Copyright © 2011-2022 走看看