Java windows上的虚假唤醒。可能吗?

Java windows上的虚假唤醒。可能吗?,java,concurrency,notifications,synchronization,wait,Java,Concurrency,Notifications,Synchronization,Wait,我最近学会了“虚假唤醒” 有人说这个问题只可能出现在某些类型的Linux PC上 我使用windows 我写了一个关于虚假唤醒的测试。我得到的结果是这是可能的。但我想给你看一下这个测试。也许我在什么地方出错了 我的初始变体: import java.util.Random; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; public class TestSpuriousWakeu

我最近学会了“虚假唤醒” 有人说这个问题只可能出现在某些类型的Linux PC上

我使用windows

我写了一个关于虚假唤醒的测试。我得到的结果是这是可能的。但我想给你看一下这个测试。也许我在什么地方出错了

我的初始变体:

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()));
    }
}
所以不同的价值观对我来说很奇怪

我添加了一对要运行的行方法:

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
在我的实验中,这真的是虚假的唤醒还是错误

附言

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

两件事

  • 即使在Windows上,虚假的唤醒也是真实的。这在WinAPI中有记录:
  • 你的测试中有一个比赛条件。所以,我认为这不太准确
  • 争用发生在工作线程中同步块的退出和到达processedThreads.incrementAndGet()时。通知程序将在这段时间内旋转,通知可能已经或可能尚未获得锁的线程

    换句话说

  • 在工作线程获取互斥对象之前,通知程序可能会旋转两次(即,notify()两次)
  • 通知程序可以在最后一个线程退出同步块但尚未到达其最终块后旋转
  • 您添加的两行更改了输出,因为通过降低通知程序的速度,您正在掩盖竞争。(给工作人员大量时间进入互斥锁。)

    希望这有点道理

    Spurious wakeups count: 0