首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么在Java中设计单例模式时需要双重检查锁?

为什么在Java中设计单例模式时需要双重检查锁?
EN

Stack Overflow用户
提问于 2019-02-20 06:40:56
回答 3查看 233关注 0票数 1

为什么我们需要在锁解除之前和之后检查null?一旦我们获得了锁,没有线程能够拥有锁,那么为什么不需要在同步块之前进行空检查呢?

代码语言:javascript
运行
复制
public class DclSingleton {
    private static volatile DclSingleton instance;
    public static DclSingleton getInstance() {
        **if (instance == null) {**
            synchronized (DclSingleton .class) {
                **if (instance == null) {**
                    instance = new DclSingleton();
                }
            }
        }
        return instance;
    }

    // private constructor and other methods...
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-02-20 06:50:11

想象下一个场景:

  1. 线程1检查instance == null并发现此条件为真。
  2. 线程2检查instance == null并发现此条件为真。
  3. 线程1获得锁定。
  4. 线程2试图获取锁,它已经被获取,所以线程2等待。
  5. 线程1初始化instance = new DclSingleton()
  6. 线程1释放锁。
  7. 线程2获得锁定。
  8. 线程2初始化instance = new DclSingleton()我们有双重初始化
票数 5
EN

Stack Overflow用户

发布于 2019-02-20 06:50:41

您检查了两次null,因为:

  1. 如果在DclSingleton.class上进行同步之前不进行检查,那么每个调用都会被同步,这可能会很慢(想象一下经常使用单例实例)。
  2. 如果您不检查null块内的synchronized,则有可能多个线程在没有机会锁定对象的情况下进行第一次检查,并且会重新创建实例。
票数 2
EN

Stack Overflow用户

发布于 2019-02-20 07:15:48

要了解为什么需要双重null检查,请看一下已经给出的答案。

安全初始化单个实例的另一种方法是静态holder模式,它将被如下所示:

代码语言:javascript
运行
复制
public class DclSingleton {

    public static DclSingleton getInstance() {
        return Holder.INSTANCE;
    }

    private static class Holder {
        private static final DclSingleton INSTANCE = new DclSingleton();
     }
}

JVM已经以线程安全的方式初始化了类,因此即使同时有2个线程访问getInstance(),JVM也只会初始化Holder类一次,这样就有了正确的初始化。

另外,Holder类将被延迟加载,因此只有在第一次引用时才会初始化它。例如,当第一次调用getInstance()

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54780284

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档