(并发专题篇)DCL-单例模式-解决并发问题的方案

这篇文章的由来

面试官:了解常用的设计模式吗?
我:了解。
面试官:说说DCL-单例模式。。。
我:不知道
面试官:。。。
⚠️设计模式是一种思想,是脱离语言的,Java有Java实现的方式,python有python的实现方式

解决的问题

多个线程操作不同实例对象,多个线程要操作同一对象,要保证对象的唯一性,如何保证实例化过程中只实例化一次?

解决的思路

1、有一个实例化的过程(只有一次),产生实例化对象
2、返回实例对象

恶汉式

实现:

在这里插入代码片/**
 * @author csw
 * @version 1.0
 * @date 2022/2/22 12:02 上午
 */

public class HungerySingleton {
    //加载的时候就产生的实例对象
    private static HungerySingleton instance = new HungerySingleton();
    private HungerySingleton(){

    }
    //返回实例对象
    private static HungerySingleton getInstance() {
        return instance;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                System.out.println(HungerySingleton.getInstance());
            }).start();
        }
    }
}

优点:

    • 线程安全性:在加载的时候已经被实例化,所以只有这一次,线程安全的

缺点:

    • 懒加载:没有延迟加载,好长时间不使用还占用空间,影响性能

⚠️:代码中加static的原因是让对象属性属于类,达到共享的目的,如果不使用private的话默认是public外部可访问,也是不安全

懒汉式

/**
 * @author csw
 * @version 1.0
 * @date 2022/2/22 12:29 上午
 */

public class HoonSingleton {
    private static HoonSingleton instance = null;
    private HoonSingleton() {
        
    }
    
    public static HoonSingleton getInstance() {
        if(null == instance) {
            instance = new HoonSingleton();
        }
        return instance;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                System.out.println(HoonSingleton.getInstance());
            }).start();
        }
    }
}

缺点:

    • 线程安全:当A线程和B线程都等于null的时候能够同时访问,不能保证实例对象的唯一性

优点:

    • 懒加载:使用的时候才去加载,性能比较好

懒汉式+同步方法

实现

/**
 * @author csw
 * @version 1.0
 * @date 2022/2/22 12:29 上午
 */

public class HoonSynSingleton {
    private static HoonSynSingleton instance = null;
    private HoonSynSingleton() {

    }

    public static synchronized HoonSynSingleton getInstance() {
        if(null == instance) {
            instance = new HoonSynSingleton();
        }
        return instance;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                System.out.println(HoonSynSingleton.getInstance());
            }).start();
        }
    }
}

优点:
线程安全,满足了懒加载条件

缺点:
加入了synchronized,退化到了串行(队列)执行,性能低

DCL(Double-Check-Locking)

/**
 * @author csw
 * @version 1.0
 * @date 2022/2/22 12:29 上午
 */

public class DCL {
    private static DCL instance = null;
    private DCL() {

    }

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

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                System.out.println(DCL.getInstance());
            }).start();
        }
    }
}

优点:

    • 线程安全
    • 懒加载
    • 性能提高了

缺点
可能会因为指令重排导致出现空指针异常

Volatile+Double-check

在这里插入图片描述
加上了Volatile就能够避免因为指令重排出现空指针异常

Holder
声明类的时候,成员变量中不声明实例变量,而放到内部静态类中
实现:

/**
 * @author csw
 * @version 1.0
 * @date 2022/2/22 1:30 上午
 */

public class HolderDemo {
    private HolderDemo(){}
    //内部类只有在实例化的时候才会去被调用
    private static class Holder{
        //加了static只能被实例化一次,因此满足了懒加载
        private volatile static HolderDemo instance = new HolderDemo();
    }

    public static HolderDemo getInstance(){
        return Holder.instance;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                System.out.println(HolderDemo.getInstance());
            }).start();
        }
    }
}

优点:
既满足了懒加载、又可以不使用synchronized锁的方式保证了线程安全
是一种使用广泛的单例模式

枚举

实现

/**
 * @author csw
 * @version 1.0
 * @date 2022/2/22 1:58 上午
 */

public class EnumSingletonDemo {
    private EnumSingletonDemo() {

    }
    //懒加载
    private enum EnumHolder{
        //常量
        INSTANCE;
        private EnumSingletonDemo instance;
        EnumHolder() {
            this.instance = new EnumSingletonDemo();
        }
        private EnumSingletonDemo getInstance() {
            return instance;
        }
    }

//恶汉式的实现
    public static EnumSingletonDemo getInstance(){
        return EnumHolder.INSTANCE.instance;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                System.out.println(EnumSingletonDemo.getInstance());
            }).start();
        }
    }
}

优点:
这种方式写的很优雅,满足了对单例模式的所有条件,也是一种特别广泛使用的方式
缺点:
比较抽象化,需要一定的基础

彩蛋

下回面试又问到这个知识点
我:DCL就是巴拉巴拉。。。,还有更好的实现方式,vdc和枚举就是巴拉巴拉。。。
面试官:牛批。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值