2014-04-25 103 views
4

我最近学会了“虚假唤醒” 任何人都说这个问题可能只适用于某些类型的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 

难道真的在我的实验虚假唤醒或错误?

P.S.

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

回答

3

两件事情

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

竞争是在工作线程中的synchronized块的退出和当它们到达processedThreads.incrementAndGet()时。通知程序将在此期间旋转,通知可能或可能未获取锁的线程。

换句话说

  1. 这是可能的通知旋转的两倍(即,通知()两次)工作线程才能获取互斥体。
  2. 通知程序可能在最后一个线程退出同步块但尚未到达其finally块后旋转。

您的两条增加的行改变了输出,因为通过减缓通告程序,您屏蔽了比赛。 (通过给Worker提供大量的时间来进入互斥锁。)

希望能有所帮助。

相关问题