一、前言

我们在使用单例模式时,一般有两种选择,一个是懒汉式,一个是饿汉式。但是这两种都是有各自的缺点,无法满足我们的需求,所以DCL(Double Check Lock双端检锁机制)出现了,一种既支持延迟加载、又支持高并发的单例实现方式。
如果不清楚懒汉式为什么不支持高并发可以看一下这篇文章--->
单例模式的懒汉模式为什么在高并发中会出现问题
其他解决方案--->

静态内部类解决单例模式中懒汉式不支持高并发,饿汉式不支持懒加载问题

利用枚举特性解决单例模式中懒汉式不支持高并发,饿汉式不支持懒加载问题

二、具体实现

- DCL单例模式

import lombok.Data;

import java.util.concurrent.atomic.AtomicInteger;

@Data
public class Phone {

    //手机余额
    private AtomicInteger count = new AtomicInteger(3);

    private Phone(){}

    private static Phone phone;

    public static Phone getInstance(){
        if (phone == null){
            synchronized(Phone.class) { // 此处为类级别的锁
               if (phone == null) {
                   phone = new Phone();
               }
            }
        }
        return phone;
    }

    public int getReduce(){
        return count.decrementAndGet();
    }

}

- 并发测试类

public class BingFa {

    public static void main(String[] args) {

        // 创建3个线程,线程里面进行加操作
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                Phone phone = Phone.getInstance();
                int reduce = phone.getReduce();
                System.out.println(Thread.currentThread().getName()+
                					"线程抢到了手机,剩余手机数量"+"-----"+reduce);
            }, String.valueOf(i)).start();
        }

    }
}

- 测试结果
在这里插入图片描述

三、总结

这样就解决了并发问题,懒汉式本来就是懒加载,我们看到三台手机被三个线程抢到了,完美解决问题!!!

附:网上有人说,这种实现方式有些问题。因为指令重排序,可能会导致 Phone对象被 new 出来,并且赋值给 phone之后,还没来得及初始化(执行构造函数中的代码逻辑),就被另一个线程使用了。要解决这个问题,我们需要给 phone成员变量加上 volatile 关键字,禁止指令重排序才行。实际上,只有很低版本的 Java 才会有这个问题。我们现在用的高版本的 Java 已经在 JDK 内部实现中解决了这个问题(解决的方法很简单,只要把对象 new 操作和初始化操作设计为原子操作,就自然能禁止重排序)。


本段话来自极客时间王老师

Q.E.D.