在JCIP 16.2中B.Goetz提到了
如果您不确保发布共享引用 发生 - 在另一个线程加载该共享引用之前,然后是 写入对新对象的引用可以重新排序(来自 线程的视角使对象()对其进行写入 字段。
所以我猜这意味着用同步发布甚至 NotThreadSafe 对象就足够了。考虑以下共享对象
public ObjectHolder{
private int a = 1;
private Object o = new Object();
//Not synchronizaed GET, SET
}
//Assume that the SharedObjectHolder published
//with enough level of synchronization
public class SharedObjectHolder{
private ObjectHolder oh;
private final Lock lock = new ReentrantLock();
public SharedObjectHolder(){
lock.lock();
try{
oh = new ObjectHolder();
} finally {
lock.unlock();
}
}
public ObjectHolder get(){
lock.lock();
try{
return oh;
} finally {
lock.unlock();
}
}
}
现在,我们在撰写oh
并从方法oh
返回get()
之前发生在之前。它保证任何调用者线程都会观察到oh
的最新值。
但是,在构建期间写入oh
字段(private int a
,private Object o
)不是happens-before
而是oh
。 JMM不保证这一点。如果我错了,请提供JMM的证明参考。因此,即使使用此类发布,读取oh
的线程也可能会观察到部分构造的对象。
那么,他说我提供的报价是什么意思?你能说清楚吗?
答案 0 :(得分:2)
如果您只按照上述方法读取或写入oh
,则get()
获取的锁将确保您在SharedObjectHolder的构造函数中查看锁定释放之前的所有操作 - 包括任何写入到oh
的字段。你所依赖的发生之前的边缘与写oh
无关,而且在发布锁定之前发生的所有与写入(包括oh
的字段)有关的事情都发生在在获取锁之前发生,这在读取之前发生。
oh
并且写入get()
,那么 可能会看到部分构造的oh
在他们两个之前发生。这就是需要安全发布SharedObjectHolder实例的原因。
(也就是说,如果您可以安全地发布SharedObjectHolder,我不明白为什么您不能安全地发布原始的oh
引用。)
答案 1 :(得分:0)
我们有:
在1,2,3和4之间存在关系,因为它们是按程序顺序并且在同一个线程中。
由于锁定,在3和4之间存在一个发生在之前的关系。
因此,由于传递性,ObjectHolder值的写入与另一个线程中的读取之间存在一个先发生的关系。
答案 2 :(得分:0)
由于您特别要求对您的陈述进行反驳:“但是,在构建期间写入oh
字段(private int a
,private Object o
)并不是happens-before
oh
。 JMM不保证“,看看JLS §17.4.5. Happens-before Order,正确的第一个项目:
如果我们有两个动作 x 和 y ,我们会写 hb(x,y)来表示 x发生 - 在y 之前。
- 如果 x 和 y 是同一个帖子的操作, x 按照程序顺序出现在 y 之前,然后 hb(x,y)。
...
这与发生 - 关系之前的传递性一起,是JMM最重要的保证,因为它意味着我们可以让线程在没有同步的情况下执行一系列操作,并且仅同步需要时。但请注意,在ObjectHolder
的字段写入和SharedObjectHolder.oh
的写入之间建立发生之前关系并不重要,因为所有这些都发生在一个单独的线程。
上面引用的重要结果是,由于程序顺序,在所有三次写入和Lock
的释放之间存在发生在之前的关系。由于Lock
的释放与Lock
内的另一个线程后续获取SharedObjectHolder.get()
之间存在发生之前关系,因此传递性建立在所有三次写入和Lock
的获取之间发生之前的关系。这三个写操作的实际执行顺序无关紧要,唯一重要的是所有三个都是在获得Lock
时完成的。
作为旁注,您在代码注释中写道“假设SharedObjectHolder以足够的同步级别发布”。如果我们假设,整个Lock
已经过时,因为用于正确发布SharedObjectHolder
实例的“足够级别的同步”也足以发布嵌入式ObjectHolder
及其字段,因为所有初始化发生在由于程序顺序而发布SharedObjectHolder
之前。