【问题标题】:What if we use only the outer null check in double check singleton pattern?如果我们在双重检查单例模式中只使用外部空检查怎么办?
【发布时间】:2019-07-05 22:44:34
【问题描述】:

问题 1:为什么在多线程的单例模式中我们需要两个空值检查?如果我们只使用外部检查呢?

    if (instance == null) {
        synchronized (ABC.class) {

            // What if we remove this check?
            if (instance == null) {
                instance = new ABC();
            }
    }

问题2:以下有什么区别:

1:直接使用synchronized()中的类名

    public ABC getInstance() {
        if (instance == null) {
            // Difference here
            synchronized (ABC.class) {
                if (instance == null) {
                    instance = new ABC();
                }
            }
         }
         return instance;
    }

2:在 synchronized() 中使用静态最终对象

    private static final Object LOCK = new Object();
    .
    .
    public ABC getInstance() {
        if (instance == null) {

             // Difference here
             synchronized (LOCK) {
                if (instance == null) {
                    instance = new ABC();
                }
             }
         }
         return instance;
    }

3:在 synchronized() 中使用 new Object()

    if (instance == null) {
    // Difference here
         synchronized (new Object()) {
            if (instance == null) {
                instance = new ABC();
            }
        }
     }

【问题讨论】:

    标签: java multithreading singleton synchronized synchronized-block


    【解决方案1】:
    1. 删除内部空检查可能会导致竞争条件。想象一下以下场景:两个线程试图同时获取对象的实例,因此它们都检查实例是否等于 null 并得到正确的答案,因此两个线程都将尝试创建对象的实例。因为这段代码是同步的,所以其中一个线程将进入同步的代码块,而另一个等待锁被释放。当第一个线程完成实例化并返回对象的实例后,锁将被释放,第二个线程将执行同步块,因此它将创建一个新实例并返回它,因为它不知道它之前已创建在它等待轮到它的时候。
    2. 在同步中使用类作为参数将生成一个静态锁。这意味着该类的所有实例都将共享锁。
    3. 如果您想用特定对象而不是类或 this 锁定同步块,则使用对象作为同步参数是有用的。这允许您在同一类中使用不同的锁来拥有不同的代码块。例如:

      Object o1 = new Object();
      Object o2 = new Object();
      synchronized(o1) {
          //your synchronized block
       }
      
      synchronized(o2){
          //other synchronized block
      }
      

    在前面的代码示例中,block1 和 block2 可以由不同的线程同时执行,因为它们使用不同的锁对象。如果您对两个代码块(即类)使用相同的锁,则块 1 将被阻塞,直到块 2 完成执行,反之亦然。

    【讨论】:

    • 这给出了一些错误信息。使用.class 与无参数不同(在非静态上下文中,没有参数作用于this,因此同步是按实例进行的,而不是按类进行的)。使用静态对象与类不同,因为类也可以被 other 事物访问,private 对象消除了这种风险。而他们的选项 3. 是没有意义的,因为每个事物都会在自己的对象上同步,这与不同步是一样的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-16
    • 2013-08-08
    • 1970-01-01
    相关资源
    最近更新 更多