多线程下的单例模式安全性

单机模式下的单例

public class SingletonDemo {
    private static SingletonDemo instace = null;
    private SingletonDemo(){
        System.out.println("enter the main method ..." );
    }
    public static SingletonDemo getInstace(){
        if(instace == null){
            instace = new SingletonDemo();
        }
        return  instace;
    }

    public static void main(String[] args) {
        System.out.println( SingletonDemo.getInstace() == SingletonDemo.getInstace());
        System.out.println( SingletonDemo.getInstace() == SingletonDemo.getInstace());
        System.out.println( SingletonDemo.getInstace() == SingletonDemo.getInstace());
        
    }
}
// main方法只进入一次,说明只new了一次对象。getInstance多次都是true 验证了单例

上述的代码在单机模式下是没有问题的,但如果此时有多个线程同时去getInstance方法,就会出问题,如下:

   public static void main(String[] args) {
       /* System.out.println( SingletonDemo.getInstace() == SingletonDemo.getInstace());
        System.out.println( SingletonDemo.getInstace() == SingletonDemo.getInstace());
        System.out.println( SingletonDemo.getInstace() == SingletonDemo.getInstace());*/

        for (int i = 0; i <= 10; i++) {
            new Thread( ()->{
                SingletonDemo.getInstace();
            },String.valueOf( i ) ).start();
        }

    }
}
// main方法进入了多次,说明单例模式创建失败,因此在多线程下,这种方式来创建单例是不可取的
//解决方案:可以给getInstance方法加synchronized关键字,但synchronized级别太重,会导致性能较差,

多线程下,如何创建高效且安全的单例模式呢?

双端检锁机制 DCL(Double Check Lock)

在加锁前后加锁后都进行为null判断。

public class SingletonDemo {
    private static SingletonDemo instace = null;
    private SingletonDemo(){
        System.out.println("enter the main method ..." );
    }
    public static SingletonDemo getInstace(){
        if(instace == null){
            synchronized(SingletonDemo.class){
                if (instace == null){
                    instace = new SingletonDemo();
                }
            }

        }
        return  instace;
    }

    public static void main(String[] args) {

        for (int i = 0; i <= 10; i++) {
            new Thread( ()->{
                SingletonDemo.getInstace();
            },String.valueOf( i ) ).start();
        }

    }
}
// 打印:enter the main method ...
// 说明:main方法进入了一次,说明单例模式创建成功

说明:DCL 不一定线程安全,因为会存在指令重排,假如volatile可以禁止指令重排。
原因在于:某个线程执行第一次检测,读到instance不为null,可能是已经分配空间,但未完成初始化。

instance = new SingltonDemo()可分为三步:

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

2,3 没有数据依赖关系,因此会发生指令重排

正确的解决方案:volatile+ DCL
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值