窗户上的虚假唤醒。 可能吗?

我最近学会了“虚假唤醒”任何人都说这个问题只适用于某些类型的Linux PC。

我用的是windows。

我写了Spurious唤醒测试。 我得到的结果是可能的。 但我想为你展示这个测试。 也许我在某处犯了错误。

我最初的变种:

import java.util.Random; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; public class TestSpuriousWakeups { static final int MAX_THREADS = 600; static final Object mutex = new Object(); static final CountDownLatch allThreadsStarted = new CountDownLatch(MAX_THREADS); static final CountDownLatch allThreadsFinished = new CountDownLatch(1); static /*final*/ volatile AtomicInteger processedThreads = new AtomicInteger(); static /*final*/ volatile AtomicInteger notifiedThreads = new AtomicInteger(); final int n = 10; static volatile boolean continueCondition = true; static final Random sleepRandom = new Random(); static class Worker extends Thread { public void run() { try { synchronized (mutex) { allThreadsStarted.countDown(); mutex.wait(); } continueCondition = true; } catch (Exception e) { throw new RuntimeException(e); } finally { processedThreads.incrementAndGet(); } } } static class Notifier extends Thread { public void run() { while (true) { if (processedThreads.get() == MAX_THREADS) break; synchronized (mutex) { doStuff(); mutex.notify(); continueCondition = false; notifiedThreads.incrementAndGet(); } } allThreadsFinished.countDown(); } // just to emulate some activity void doStuff() { try { Thread.sleep(sleepRandom.nextInt(5)); } catch (InterruptedException e) { throw new RuntimeException(e); } } } public static void main(String[] args) throws Exception { for (int i = 0; i < MAX_THREADS; i++) new Worker().start(); // wait for all workers to start execution allThreadsStarted.await(); new Notifier().start(); // wait for all workers and notifier to finish execution allThreadsFinished.await(); System.out.println("Spurious wakeups count: " + (MAX_THREADS - notifiedThreads.get())); } } 

4随机执行:

 Spurious wakeups count: -20 Spurious wakeups count: -5 Spurious wakeups count: 0 Spurious wakeups count: -407 

所以不同的价值观让我感到疑惑。

我添加了一对行来运行方法:

 static class Notifier extends Thread { public void run() { while (true) { while (!continueCondition) //added string doStuff(); //added string // all threads finished their execution if (processedThreads.get() == MAX_THREADS) break; synchronized (mutex) { doStuff(); mutex.notify(); continueCondition = false; notifiedThreads.incrementAndGet(); } } allThreadsFinished.countDown(); } 

在它之后,我不能得到别的东西

 Spurious wakeups count: 0 

我的实验中真的是虚假的唤醒或错误吗?

PS

我注意到我看到负数。 因此显然它是实验bug。 但我不明白原因。

两件事情

  1. 即使在Windows上,虚假的唤醒也是真实的。 这在WinAPI中有记录: http : //msdn.microsoft.com/en-us/library/windows/desktop/ms682052( v = vs.85) .aspx
  2. 你的考试中有竞争条件。 所以,我认为这不是很准确。

竞争是在工作线程中同步块的退出与它们到达processedThreads.incrementAndGet()之间。 通知程序将在此期间旋转,通知可能已获取或未获得锁定的线程。

换一种说法

  1. 在工作者线程可以获取互斥锁之前,Notifier可能会旋转两次(即notify()两次)。
  2. 在最后一个线程退出同步块但尚未到达其finally块之后,Notifier可能会旋转。

你添加的两行会改变输出,因为通过减慢通知程序,你就会掩盖比赛。 (通过给工人很多时间进入互斥锁。)

希望有一定道理。