当前位置: 首页 > 面试题库 >

安全发布对象的最终vs易失性担保

楚俊迈
2023-03-14
问题内容

从实践中的Java并发性书中:

为了安全地发布对象,必须同时使对该对象的引用和该对象的状态对其他线程可见。可以通过以下方式安全地发布正确构造的对象:

  • 从静态初始化程序初始化对象引用

  • 将对它的引用存储到volatile字段或AtomicReference中

  • 将对其的引用存储到正确构造的对象的最终字段中

  • 将对它的引用存储到由
    锁适当保护的字段中。

我的问题是:

  1. 项目符号点2和3之间有什么区别?我对volatile方法final方法在安全发布对象方面的区别感兴趣。
  2. 在点3中, 正确构造的物体 的最终场 他意味着什么?在开始要点之前,作者已经提到他们正在谈论一个正确构造的对象(我认为不会让this引用转义)。但是他们又为什么提到适当构造的对象呢?

问题答案:

项目符号点2和3之间有什么区别?

  • volatile基本上意味着对该字段的任何写入都将从其他线程可见。因此,当您将字段声明为volatile:时private volatile SomeType field;,可以确保如果构造函数向该field:写入内容,则field = new SomeType();其他随后尝试读取的线程将看到此分配field
  • final具有相似的语义:如果有一个final字段,则可以保证:private final SomeType field;对该字段的写入(在声明中或在构造函数中): 如果对象正确,field = new SomeType();将不会重新编写该字段,并且其他线程可以看到该字段 已发布this例如,无法逃脱)。

显然,主要区别在于,如果该字段为final,则只能分配一次。

在点3中,正确构造的物体的最终场对他意味着什么?

例如,如果让您this脱离构造函数,则最终语义所提供的保证将消失:观察线程可能会看到具有其默认值的字段(对象为null)。如果对象构造正确,则不会发生。

人为的例子:

class SomeClass{
    private final SomeType field;

    SomeClass() {
        new Thread(new Runnable() {
            public void run() {
                SomeType copy = field; //copy could be null
                copy.doSomething(); //could throw NullPointerException
            }
        }).start();
        field = new SomeType();
    }
}


 类似资料:
  • 问题内容: 即使经过了这一点,我仍然不清楚在以下代码中使用final如何导致安全发布。有人可以给出一个易于理解的解释吗? 问题答案: 编辑添加:关于Java和JSR-133 行为起源的 有趣观点。 有关如何在新JMM中正常工作的规范参考,以确保安全发布:http : //www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#finalRigh

  • 我的问题是: 项目符号2和3有什么区别?我对方法和方法在对象的安全发布方面的区别感兴趣。 他在第3点中所说的正确构造对象的final field是什么意思?在开始这些项目符号之前,作者已经提到了他们正在讨论一个正确构造的对象(我假定它不会让引用转义)。但是他们为什么要提到正确构造的对象?

  • 及其不安全的发布: 可以抛出AssertionError,我同意。作者写道,这是因为不安全的出版,但另一方面没有答案:什么才是正确的出版方式?它们表示了4个安全发布习惯用语,但我不明白,为什么它们会在上面的情况下起作用: 要安全地发布对象,必须同时使对对象的引用和对象的状态对其他线程可见。通过以下方法可以安全地发布构造正确的对象: null 这里是我的第一个问题,谢谢你的帮助!

  • 问题内容: 重要的编辑* 我知道发生 两个分配的线程中 的“发生在前面” , 我的问题是,当“ a”仍然为空时, 另一个 线程是否有可能读取“ b”为非空。因此,我知道,如果您从与先前调用 setBothNonNull(…)的 线程相同的线程中调用 doIt() ,则它不会引发NullPointerException。但是,如果一个调用 doIt方法() 从另一个线程 不同于调用 setBothN

  • 每个方法将一个排入队列,以便在另一个线程上执行。在后台线程上调用来执行某些任务,在UI线程上调用来显示结果。 如果我们假设返回一个可变的、未同步的列表,例如ArrayList,那么赋值给的最后一个参数是否可以确保列表的安全发布,还是需要采取额外的步骤来确保安全发布?

  • 问题内容: 阅读“实践中的Java并发性”,第3.5节包含以下内容: 除了创建两个的明显的线程安全隐患外,该书还声称可能会发生发布问题。 此外,对于诸如 一个可以扔! 这怎么可能?我能想到的唯一允许这种荒谬行为的方法是,如果构造函数不被阻塞,那么当构造函数代码仍在另一个线程中运行时,将创建对实例的引用。 这可能吗? 问题答案: 之所以可行,是因为Java的内存模型较弱。它不保证读写顺序。 可以通过