我对 Java 的发生之前和同步有一点分歧。
想象以下场景:
主线程
MyObject o = new MyObject(); // (0)
synchronized (sharedMonitor) {
// (1) add the object to a shared collection
}
// (2) spawn other threads
其他主题
MyObject o;
synchronized (sharedMonitor) {
// (3) retrieve the previously added object
}
// (4) actions to modify the object
请注意, 的实例变量MyObject
既不是volatile
,也不是final
。的方法MyObject
不使用同步。
我的理解是:
1 发生在 3之前,因为在同一个监视器上存在同步,并且其他线程仅在2产生,它在1之后执行。
4上的操作不能保证稍后对主线程可见,除非所有线程都有进一步的同步,并且主线程在这些操作之后以某种方式同步。
问:是否可以保证0处的操作可见、发生之前、3上的并发访问,或者我必须将变量声明为volatile
?
现在考虑以下场景:
主线程
MyObject o = new MyObject(); // (0)
synchronized (sharedMonitor) {
// (1) add the object to a shared collection
}
// (2) spawn other threads, and wait for their termination
// (5) access the data stored in my object.
其他主题
MyObject o;
synchronized (sharedMonitor) {
// (3) retrieve the previously added object
}
o.lock(); // using ReentrantLock
try {
// (4) actions to modify the object
} finally { o.unlock(); }
我的理解是:
1 发生在 3之前,就像以前一样。
4上的操作在其他线程之间是可见的,
ReentrantLock
因为MyObject
.4上的操作在逻辑上发生在3之后,但是由于在不同的监视器上同步,从3到4没有发生之前的关系。
即使在 4 之后有同步,上述观点仍然
sharedMonitor
适用。unlock
4上的操作不会在5上的访问之前发生,即使主线程等待其他任务终止。这是由于5上的访问没有与 同步,所以主线程可能仍然看到过时的数据。
o.lock()
问:我的理解正确吗?