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

在Java中的双重检查锁定中易失性[重复]

濮升
2023-03-14

据我所知,这是Java中双重检查锁定模式的正确实现(自Java5):

class Foo {
    private volatile Bar _barInstance;
    public Bar getBar() {
        if (_barInstance == null) {
            synchronized(this) { // or synchronized(someLock)
                if (_barInstance == null) {
                    Bar newInstance = new Bar();
                    // possible additional initialization
                    _barInstance = newInstance;
                }
            }
        }
        return _barInstance;
    }
}

我想知道缺少volatile是一个严重的错误,还是一个可能存在性能缺陷的轻微缺陷,假设\u barInstance只能通过getBar访问。

我的想法是这样的:同步引入了事前发生关系。初始化_barInstance的线程将其值写入离开同步块的主存储器。因此,即使不是易失性的,也不会有_barInstance的双重初始化:其他线程的_barInstance本地副本中有null(在第一次检查中得到true),但是必须在进入同步块后的第二次检查中从主存储器中读取新值(getfalse并且不进行重新初始化)。因此,唯一的问题是每个线程获取过多的锁。

据我所知,它在CLR中是正确的,我相信它在JVM中也是正确的。我说得对吗?

非常感谢。

共有1个答案

梁兴修
2023-03-14

在以下情况下,不使用volatile可能会导致错误:

  • 线程1输入getBar()并发现_barInstancenull
  • 线程1尝试创建一个Bar对象并更新对_barInstance的引用。由于某些编译器优化,这些操作可能会无序完成。
  • 同时,线程2输入getBar()并看到一个非空的_barInstance,但可能会在_barInstance对象的成员字段中看到默认值。它基本上看到一个部分构造的对象,但引用不是null。

易失性修饰符将禁止写入或读取变量_barInstance相对于任何先前的读取或写入。因此,它将确保线程2不会看到部分构造的对象。

更多详情:http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

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

  • 我使用Java大约一个月了,在编程方面仍然是一个一般的业余爱好者,所以如果我有什么不对的地方,请随时纠正我。也许我会提供一些多余的细节,但我现在是如此困惑,我无法决定什么是重要的。 所以,我一直在开发多线程客户机-服务器应用程序。所有线程都在使用同一个对象,其中存储了某些配置值和共享记录器;此对象在server-thread中初始化,然后作为参数传递给client-thread类构造函数。首先,假

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

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

  • 问题内容: 我想为Java中的多线程实现延迟初始化。 我有一些这样的代码: 我得到了“双重检查锁定已损坏”声明。 我该如何解决? 问题答案: 以下是第71项中建议的惯用语:明智地使用 Effective Java: 如果你需要使用延迟初始化来提高实例字段的性能,请使用double-check idiom。这种习惯用法避免了在初始化字段后访问字段时发生锁定的费用(项67)。习惯用法的想法是检查字段的

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