我的问题是:
volatile
方法和final
方法在对象的安全发布方面的区别感兴趣。this
引用转义)。但是他们为什么要提到正确构造的对象?要点2和要点3的区别是什么?
volatile
基本上意味着对该字段的任何写入都将从其他线程可见。因此,当您将一个字段声明为volatile:private volatile SomeType field;
时,可以保证如果构造函数写入该字段:field=new SomeType();
,则随后尝试读取field
的其他线程将可见此赋值。final
具有非常相似的语义:您可以保证,如果您有一个final字段:private final SomeType字段;
对该字段的写入(无论是在声明中还是在构造函数中):field=new SomeType();
如果对象正确发布(例如,this
没有转义),则不会被重新写入,并且将被其他线程可见。很明显,主要的不同之处在于,如果字段是final,则只能赋值一次。
他在第3点中所说的正确构造对象的最终场是什么意思?
例如,如果让this
从构造函数转义,那么最终语义提供的保证就会消失:观察线程可能会看到具有默认值的字段(对象为空)。如果对象构造正确,这是不可能发生的。
虚构的示例:
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();
}
}
及其不安全的发布: 可以抛出AssertionError,我同意。作者写道,这是因为不安全的出版,但另一方面没有答案:什么才是正确的出版方式?它们表示了4个安全发布习惯用语,但我不明白,为什么它们会在上面的情况下起作用: 要安全地发布对象,必须同时使对对象的引用和对象的状态对其他线程可见。通过以下方法可以安全地发布构造正确的对象: null 这里是我的第一个问题,谢谢你的帮助!
问题内容: 阅读“实践中的Java并发性”,第3.5节包含以下内容: 除了创建两个的明显的线程安全隐患外,该书还声称可能会发生发布问题。 此外,对于诸如 一个可以扔! 这怎么可能?我能想到的唯一允许这种荒谬行为的方法是,如果构造函数不被阻塞,那么当构造函数代码仍在另一个线程中运行时,将创建对实例的引用。 这可能吗? 问题答案: 之所以可行,是因为Java的内存模型较弱。它不保证读写顺序。 可以通过
问题内容: 即使经过了这一点,我仍然不清楚在以下代码中使用final如何导致安全发布。有人可以给出一个易于理解的解释吗? 问题答案: 编辑添加:关于Java和JSR-133 行为起源的 有趣观点。 有关如何在新JMM中正常工作的规范参考,以确保安全发布:http : //www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#finalRigh
由于引用字段lastLogin没有任何字段的属性来保证可见性(final、volatile、guarded或由静态初始化器初始化),我认为映射本身可能不会以完全构造的状态显示给其他线程,因此本末倒置。还是我错过了什么?
从静态初始值设定项初始化对象引用 将对它的引用存储到volatile字段或atomicreference 将对它的引用存储到正确构造的对象的最后一个字段 将对它的引用存储到由锁正确保护的字段中。 但是,我对第二个成语感到困惑。因为只能保证引用对另一个线程是可见的,但它没有它所引用的对象构造的同步。那么它如何保证可变对象是正确构造的,构造这个对象的线程是什么,被另一个线程打断了呢?
问题内容: 从实践中的Java并发性书中: 为了安全地发布对象,必须同时使对该对象的引用和该对象的状态对其他线程可见。可以通过以下方式安全地发布正确构造的对象: 从静态初始化程序初始化对象引用 将对它的引用存储到volatile字段或AtomicReference中 将对其的引用存储到正确构造的对象的最终字段中 将对它的引用存储到由 锁适当保护的字段中。 我的问题是: 项目符号点2和3之间有什么区