DCL(Double Check Lock双重检锁机制)解决单例模式中懒汉式不支持高并发,饿汉式不支持懒加载问题
一、前言
我们在使用单例模式时,一般有两种选择,一个是懒汉式,一个是饿汉式。但是这两种都是有各自的缺点,无法满足我们的需求,所以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 操作和初始化操作设计为原子操作,就自然能禁止重排序)。
本段话来自极客时间王老师