当前位置: 首页 > 知识库问答 >
问题:

为什么不可变对象在双重检查锁定中是安全的?

霍永年
2023-03-14

可变一的示例和说明如下:

// Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo { 
  private Helper helper = null;
  public Helper getHelper() {
    if (helper == null) 
      synchronized(this) {
        if (helper == null) 
          helper = new Helper();
      }    
    return helper;
    }
  // other functions and members...
  }

它不起作用的第一个原因

它不起作用的最明显的原因是初始化Helper对象的写操作和对Helper字段的写操作可能不按顺序进行或被感知。因此,调用getHelper()的线程可以看到对helper对象的非空引用,但看到的是helper对象字段的默认值,而不是构造函数中设置的值。

谢谢

共有1个答案

慕金林
2023-03-14

通常对象的代码被“破坏”的原因是helper可能是非空的,但它指向的对象还没有完全初始化,正如您在引文中所解释的那样。

但是,如果Helper类是不可变的,这意味着它的所有字段都是最终的,那么Java内存模型保证它们是安全发布的,即使对象通过数据竞争获得可用(在您的示例中就是这样):

final字段还允许程序员在没有同步的情况下实现线程安全的不可变对象。线程安全的不可变对象被所有线程视为不可变的,即使使用数据竞争在线程之间传递对不可变对象的引用。这可以提供安全保证,防止不正确或恶意代码误用不可变类。final字段必须正确使用,以提供不变性的保证。

 类似资料:
  • 问题内容: 此问题与旧Java版本的行为以及双重检查锁定算法的旧实现有关 较新的实现使用volatile并依赖于略有更改的语义,因此它们 不会 损坏。 声明字段分配始终是原子的,除了long或double字段。 但是,当我阅读解释为什么双重检查锁定被破坏时,据说问题出在赋值操作中: 线程A注意到该值未初始化,因此它获得了锁并开始初始化该值。 由于某些编程语言的语义,允许编译器生成的代码在A完成执行

  • 问题内容: 在设计模式手册中,具有双重检查锁定的单例模式已实现如下: 我不明白为什么要使用它。使用不会 违反使用双重检查锁定(即性能)的目的吗? 问题答案: 真正的问题是可能在完成构造之前为其分配存储空间。将看到该作业并尝试使用它。由于使用的是的部分构造版本,因此导致失败。

  • 问题内容: 我偶然遇到了一篇文章,该文章最近讨论了Java中的双重检查锁定模式及其陷阱,现在我想知道我多年来使用的那种模式的变体是否会遇到任何问题。 我看过许多关于该主题的文章和文章,并了解了对部分构造的对象的引用所带来的潜在问题,据我所知,我认为我的实现不受这些问题的影响。以下模式是否有问题? 而且,如果没有,人们为什么不使用它?在围绕此问题进行的任何讨论中,我从未见过推荐它的方法。 问题答案:

  • 本文向大家介绍Java线程安全的Singleton具有双重检查的锁定,包括了Java线程安全的Singleton具有双重检查的锁定的使用技巧和注意事项,需要的朋友参考一下 示例 这种类型的Singleton是线程安全的,并且可以在创建Singleton实例之后防止不必要的锁定。 Java SE 5 必须强调的是-在Java SE 5之前的版本中,上述实现是错误的,应避免使用。在Java 5之前的J

  • 问题内容: 看到这个答案。它说: 六个非常糟糕的例子; … 锁定在可变字段上。例如,synced(object){object = …; } 锁定可变字段有什么问题?如果被声明为但不是不可变的类怎么办? 问题答案: 这是一个坏主意,因为如果另一个线程更改了关键部分中的引用,则这些线程将不再看到相同的引用,因此它们将不会在同一对象上同步,从而不受控制地运行。例: 假设有2个线程试图进入此关键部分。线

  • 问题内容: 为什么Redux中的对象是不可变的?我知道某些框架(例如Angular2)将使用onPush并可以利用不变性来比较视图状态以更快地呈现,但是我想知道是否还有其他原因,因为Redux与框架无关,但它在其自己的文档中提到要使用不变性(与框架无关)。 感谢任何反馈。 问题答案: Redux是一个小型库,将状态表示为(不可变的)对象。和 新状态 通过将当前状态传递给纯函数来创建全新的对象/应用