内存与同步互斥锁不一致

时间:2014-06-12 02:26:42

标签: java multithreading synchronization

更新 当我第一次发布这个时,我相当肯定代码被破坏了。现在,我不再确定自己观察到了什么。我遇到的最大问题是,我似乎无法应用17.4. Memory Model并直接说明


以下代码已损坏。

它试图实现的目标过于复杂,但此外,它的线程不安全,因为我发现它可以无限期地等待{{1} }。我并不担心前者(可以使用cReentrantLock来表示更健全的代码),但我想知道后者的原因是什么?

CountDownLatch

我已经考虑过 happens-befores

  • hb(f,h) hb(h,a)因此 hb(f,a)
  • hb(c,d) hb(d,e)因此 hb(c,e)

但是,这似乎并不能证明或反驳任何事情。

编辑(以上问题未能真正解释此代码应执行的操作。)

预期:

  • 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等待的线程正在等待。

1 个答案:

答案 0 :(得分:1)

可能是一个线程在另一个线程开始等待()之前调用notifyAll()的情况。这可能是由spurious wakeup

引起的
  • 主题1进入关键部分
  • 线程2开始等待()
  • 在线程2中发生虚假唤醒
  • 线程1进入同步块并通知锁
  • 线程2进入同步块并无限期等待

或者线程1恰好在线程2之前执行。虽然你的代码在JMM方面是正确的,但它的liveness并不能保证。这就是为什么你应该使用CountDownLatch而不是通知/等待机制。