gpt4 book ai didi

java - Windows 上的虚假唤醒。是否可以?

转载 作者:搜寻专家 更新时间:2023-11-01 03:05:45 24 4
gpt4 key购买 nike

我最近学会了“虚假唤醒”有人说这个问题只可能出现在某些类型的 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()));
}
}

4随机执行:

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

如此不同的值(value)观让我感到疑惑。

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

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

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

附言

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

最佳答案

两件事

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

竞争发生在工作线程中同步块(synchronized block)的退出和它们到达 processedThreads.incrementAndGet() 之间。通知程序将在这段时间内自旋,通知可能已获得或未获得锁的线程。

换句话说

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

你添加的两条线改变了输出,因为通过减慢通知程序,你掩盖了比赛。 (通过给 Worker 大量时间来进入互斥量。)

希望这是有道理的。

关于java - Windows 上的虚假唤醒。是否可以?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23296260/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com