Reputation: 37098
I recently learned "Spurious wakeups" Any people say that this problem possible only for some types of Linux PC.
I use windows.
I wrote test for Spurious wakeups. I got result that it is possible. But I want to show this test for you. Maybe I made mistake somewhere.
my initial variant:
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 random execution:
Spurious wakeups count: -20
Spurious wakeups count: -5
Spurious wakeups count: 0
Spurious wakeups count: -407
So different values is wondering for me.
I added pair of rows to run method:
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();
}
after it I cannot get something another than
Spurious wakeups count: 0
Is it really Spurious wakeups or bug in my experiment ?
P.S.
I noticed that I see negatives numbers. Thus obviously it is experiment bug. But I don't understand cause.
Upvotes: 4
Views: 835
Reputation: 2121
Two things
The race is between the exit of the synchronized block in your worker threads and when they reach processedThreads.incrementAndGet(). Notifier will spin during that time, notifying threads which may or may not have acquired the lock.
In other words
Your two added lines change the output because, by slowing down the Notifier, you're masking the race. (By giving Worker lots of time to enter the mutex.)
Hope that makes some sense.
Upvotes: 3