I have N threads that do these things in loop: increase shared variable, checks if shared variable value is N (if so put value to queue) and do wait(). I have one more threat that checks the q variable. If queue is true, it does notifyAll(). After that N threads should wake up, and do another run of loop. But it seems that some threads are waking up without notification. I've read about spurious wakeups, but I don't know what condition should I put to while() to check if it was spurious wake up.
Bellow is example of my code (not the same, but very similar in meaning):
Shared class is shared between all threads:
class Shared {
volatile int v = 0;
}
I create 10 threads and run them.
class NThreads implements Runnable {
private Shared shared;
private QThread q;
static int N = 0; /* N - number of threads */
public NThreads(QThread q, Shared shared) {
this.q = q;
this.shared = shared;
++N;
}
@Override
public void run() {
for (int i=0;i<1048575;++i) {
doSomeCalculations();
loop();
}
}
private void loop() {
synchronized (shared) {
if (++shared.v == N) {
shared.v = 0;
synchronized (Q) {
q.q = true;
}
shared.wait();
} else {
shared.wait();
}
}
}
}
There is only one QThread that waits for modification of q and then invoke notifyAll();
class QThread implements Runnable {
private Shared shared;
volatile boolean q = false;
public QThread(Shared shared) {
this.shared = shared;
}
@Override
public void run() {
for (;;) {
if (q) {
synchronized (this) {
q = false;
}
synchronized (shared) {
shared.notifyAll();
}
}
doSomethingElse();
// or even: Thread.yield();
}
}
}
Main class that runs everything:
class Main {
public static void main(String[] args) {
Shared shared = new Shared();
QThread qt = new QThread(shared);
NThread[] nt = new NThread[10];
for (int i=0; i<nt.length; ++i) {
nt[i] = new NThread(qt, shared);
}
Thread[] threads = new Thread[nt.length+1];
threads[0] = new Thread(qt);
for (int i=0; i<nt.length; ++i) {
threads[1+i] = new Thread(nt[i]);
}
for (int i=0; i<threads.length; ++i) {
threads[i].start();
}
for (int i=0; i<threads.length; ++i) {
threads[i].join();
}
}
}
Sometimes there are threads (from NThreads) that finishes their loops, but other threads no. I think that is because of spurious wakeups. How to write condition to take cake of spurious wakeups and be sure that all threads can continue their work?
Maybe there is useful class in java.util.concurrent? But I didn't see anything interesting... :(