更新
当我第一次发布这个时,我相当肯定代码被破坏了。现在,我不再确定自己观察到了什么。我遇到的最大问题是,我似乎无法应用17.4. Memory Model并直接说明
以下代码已损坏。 它试图实现的目标过于复杂,但此外,它的线程不安全,因为我发现它可以无限期地等待{{1} }。我并不担心前者(可以使用 我已经考虑过 happens-befores : 但是,这似乎并不能证明或反驳任何事情。 编辑(以上问题未能真正解释此代码应执行的操作。) 预期: 实际:
c
或ReentrantLock
来表示更健全的代码),但我想知道后者的原因是什么? CountDownLatch
static final ConcurrentHashMap<Integer, Object> mutex = new ConcurrentHashMap<>();
public static brokenFoo() {
Object ourLock = new Object();
for (;;) {
Object theirLock = mutex.putIfAbsent(0, ourLock);
if (theirLock == null) {
break;
}
synchronized (theirLock) { // a
if (mutex.get(0) != theirLock) { // b
continue;
}
theirLock.wait(); // c
} // d
}
try {
// critical section
} finally {
synchronized (ourLock) { // e
mutex.remove(0); // f
ourLock.notifyAll(); // g
} // h
}
}
由多个线程调用,上述代码应该提供brokenFoo()
上的互斥。// critical section
,则只有一个会进入brokenFoo()
,而其他人则先等待某个地方。// critical section
中的帖子退出后,另一个人应继续取代它。
// critical section
中没有其他线程在c
等待的线程正在等待。
答案 0 :(得分:1)
可能是一个线程在另一个线程开始等待()之前调用notifyAll()的情况。这可能是由spurious wakeup:
引起的或者线程1恰好在线程2之前执行。虽然你的代码在JMM方面是正确的,但它的liveness并不能保证。这就是为什么你应该使用CountDownLatch而不是通知/等待机制。