[英]Spurious wakeups on windows. Is it possible?
我最近学到了“虚假唤醒”任何人都说这个问题只适用于某些类型的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。 但我不明白原因。
两件事情
竞争是在工作线程中同步块的退出与它们到达processedThreads.incrementAndGet()之间。 通知程序将在此期间旋转,通知可能已获取或未获得锁定的线程。
换一种说法
你添加的两行会改变输出,因为通过减慢通知程序,你就会掩盖比赛。 (通过给工人很多时间进入互斥锁。)
希望这有点道理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.