28

This question is not about, whether spurious wakeups actually happen, because this was already discussed in full length here: Do spurious wakeups in Java actually happen? Therefore this is also not about, why I do have to put a loop around my wait Statement. What this is about:

I would like to construct a case, where the spurious wake-up happens. What I've learned so far in the question linked above is this:

If a Linux process is signaled its waiting threads will each enjoy a nice, hot spurious wakeup.

So it seems this will only work a linux machine, in fact I have Ubuntu 11.04 - 64-Bit. I have written a Java program with one thread waiting for a condition, but without loop and another class on which a thread just waits and get notified by another thread. I thought launching all three threads in one JVM would force the case described above, but it seems like this is not the case.

Has anyone else another idea how to construct such a case in Java?

Archie
  • 4,959
  • 1
  • 30
  • 36
Konrad Reiche
  • 27,743
  • 15
  • 106
  • 143
  • From what I can gather reading a lot of reference material, it tends to happen when a lot of multithreaded I/O is happening (look up EINTR for Linux C programming). I don't think you can force one unless you can find (or write!) a p-threads implementation that forces one intentionally. –  Jul 22 '11 at 10:49
  • @platzhirsch: Is this question/bounty about Java xor Pthreads? AFAIK the usual Java implementations don't use neither `pthread_mutex` nor `phread_cond`. `java.util.concurrent` uses a custom implementation based on atomic primitives. – A.H. Oct 18 '11 at 10:22
  • @A.H.: This question is about Java threads. The Java thread which is waiting on a condition with Object.wait() – Konrad Reiche Oct 18 '11 at 15:05

7 Answers7

18

You can't force a spurious wakeup, but to the running thread, a spurious wakeup is indistinguishable from a regular wakeup (the source of the event is different, but the event itself is the same)

To simulate a spurious wakeup, simply call notify();

Calling interrupt() isn't suitable, because doing so sets the interrupt flag, and after a spurious wakeup, the interrupt flag is not set

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 1
    I have not understand why I cannot force a spurious wakeup. Thread.interrupt() is quite boring to my mind, since you have to guard wait() against an InterruptedException anyway so this will not come very suprising. – Konrad Reiche Jul 14 '11 at 23:18
  • 5
    @Bohemian - I don't think this is right. An interrupt results in an `InterruptedException`, not a normal return from the `wait` call. If you've implemented your code correctly (i.e. you don't squash the exception), the behaviour is different. – Stephen C Jul 15 '11 at 01:04
  • 2
    @Bohemian, interrupt does basically the same as `notify()` but also sets the `interrupted` flag. You can consider `notify()` as taking the head waiting thread and interrupting it w/o setting the `interrupted` flag (no flag - no exception). Spurious wake-up happen w/o an explicit signal (it can be generated by the threading lib or the OS), hence there is no `interrupted` flag set. – bestsss Jul 19 '11 at 10:06
  • You guys are correct - it's like a notify(), *not* an interrupt(). Thx for caring enough to share :) – Bohemian Jul 23 '11 at 04:19
  • 1
    So after all this case is specified and so we have to guard against it, but it will never occur anyway. Is that the resolution? – Konrad Reiche Oct 18 '11 at 15:07
  • @platzhirsch Yes. The JVM spec says that it *can* happen, so you should always write your code defensively so you handle the situation. The thing to remember is after a spurious wakeup, the state change that would normally have caused a wakeup will not be correct, so always check for correct state after wakeup before taking action. – Bohemian Oct 18 '11 at 20:05
  • The last comment by @Bohemian seems right on - the spec says it's possible, so you should guard against it, whether or not it ever happens in practice. (e.g., It may not happen in practice now, but the implementation may change in the future s.t. it does, and the Java interface needn't change when that happens since it already says this is a possibility.) – Dave Lillethun Jul 08 '13 at 18:05
  • From my understanding (which is mostly based on reading other Qs on SO)... It seems whether spurious wakeups occur and why is somewhat platform dependant. That may be why the Java spec says it's possible but it vague about when/why. For example, Linux signals (man 7 signal) wake up all blocked system calls, whether it's their time to wake up or not. The JRE apparently uses `pthread_cond_wait` (man 3 pthread_cond_wait) internally, so if you send a Java process on Linux a signal, the pthread_cond_wait will wake up. Obviously _this_ cause doesn't appen in JRE implementaitons for Windows, however. – Dave Lillethun Jul 08 '13 at 18:12
10

"Spurious wakeup" is a hotchpotch and covers any implementation detail in that realm. Therefore it is quite hard to make out what a "real" spurious wakeup is and why another one is "unreal" - let alone on which layer this implementation detail originates. Choose any one from "kernel", "system library (libc)", "JVM", "Java standart library (rt.jar)" or a custom framework built on top of this stack.

The following program shows a spurious wakeup using java.util.concurrent stuff:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SpuriousWakeupRWLock {
    static Lock lock = new ReentrantLock();
    static Condition condition = lock.newCondition();
    static int itemsReady;

    public static void main(String[] args) throws Exception {

        // let consumer 1 enter condition wait
        new ConsumerOne().start();
        Thread.sleep(500);

        lock.lock();
        try {
            // let consumer 2 hit the lock
            new ConsumerTwo().start();
            Thread.sleep(500);

            // make condition true and signal one (!) consumer
            System.out.println("Producer: fill queue");
            itemsReady = 1;
            condition.signal();
            Thread.sleep(500);
        }
        finally {
            // release lock
            lock.unlock();
        } 

        System.out.println("Producer: released lock");
        Thread.sleep(500);
    }

    abstract static class AbstractConsumer extends Thread {
        @Override
        public void run() {
            lock.lock();
            try {
                consume();
            } catch(Exception e){
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        abstract void consume() throws Exception;
    }

    static class ConsumerOne extends AbstractConsumer {
        @Override
        public void consume() throws InterruptedException {
            if( itemsReady <= 0 ){      // usually this is "while"
                System.out.println("One: Waiting...");
                condition.await();
                if( itemsReady <= 0 )
                    System.out.println("One: Spurious Wakeup! Condition NOT true!");
                else {
                    System.out.println("One: Wakeup! Let's work!");
                    --itemsReady;
                }
            }
        }
    }

    static class ConsumerTwo extends AbstractConsumer {
        @Override
        public void consume() {
            if( itemsReady <= 0 )
                System.out.println("Two: Got lock, but no work!");
            else {
                System.out.println("Two: Got lock and immediatly start working!");
                --itemsReady;
            }
        }
    }
}

Output :

One: Waiting...
Producer: fill queue
Producer: released lock
Two: Got lock and immediatly start working!
One: Spurious Wakeup! Condition NOT true!

The used JDK was:

java version "1.6.0_20"
OpenJDK Runtime Environment (IcedTea6 1.9.9) (6b20-1.9.9-0ubuntu1~10.04.2)
OpenJDK 64-Bit Server VM (build 19.0-b09, mixed mode)

It is based on one implementation detail in java.util.concurrent: The standard Lock has one waiting queue, the Condition has another waiting queue. If the condition is signalled, the signalled thread is moved from the condition's queue into the lock's queue. The implementation detail: It is moved at the end of the queue. If another thread is already waiting in the lock queue and this second thread did not visit the condition variable, this thread can "steal" the signal. If the implementation would have put the first thread before the second thread, this would not have happened. This "bonus" could/would be based on the fact that the first thread has got the lock already once and that the waiting time in the condition associated with the same lock is credited to that thread.

I define this as "spurious" because

  • the condition has been signalled only once,
  • only one thread has been awoken by the condition
  • but the thread awoken by the condition found it was not true
  • the other thread was never touching the condition and is therefore "lucky but innocent"
  • a slightly other implementation would have prevented this.

The last point is demonstrated with this code using Object.wait():

public class SpuriousWakeupObject {
    static Object lock = new Object();
    static int itemsReady;

    public static void main(String[] args) throws Exception {

        // let consumer 1 enter condition wait
        new ConsumerOne().start();
        Thread.sleep(500);

        // let consumer 2 hit the lock
        synchronized (lock) {
            new ConsumerTwo().start();
            Thread.sleep(500);

            // make condition true and signal one (!) consumer
            System.out.println("Producer: fill queue");
            itemsReady = 1;
            lock.notify();

            Thread.sleep(500);
        } // release lock
        System.out.println("Producer: released lock");
        Thread.sleep(500);
    }

    abstract static class AbstractConsumer extends Thread {
        @Override
        public void run() {
            try {
                synchronized(lock){
                    consume();
                }
            } catch(Exception e){
                e.printStackTrace();
            }
        }
        abstract void consume() throws Exception;
    }

    static class ConsumerOne extends AbstractConsumer {
        @Override
        public void consume() throws InterruptedException {
            if( itemsReady <= 0 ){      // usually this is "while"
                System.out.println("One: Waiting...");
                lock.wait();
                if( itemsReady <= 0 )
                    System.out.println("One: Spurious Wakeup! Condition NOT true!");
                else {
                    System.out.println("One: Wakeup! Let's work!");
                    --itemsReady;
                }
            }
        }
    }

    static class ConsumerTwo extends AbstractConsumer {
        @Override
        public void consume() {
            if( itemsReady <= 0 )
                System.out.println("Two: Got lock, but no work!");
            else {
                System.out.println("Two: Got lock and immediatly start working!");
                --itemsReady;
            }
        }
    }
}

Output:

One: Waiting...
Producer: fill queue
Producer: released lock
One: Wakeup! Let's work!
Two: Got lock, but no work!

Here the implementation seems to do as I would expect it: The thread using the condition is awoken first.

Final note: The idea for the principle comes from Why does java.util.concurrent.ArrayBlockingQueue use 'while' loops instead of 'if' around calls to await()? , although my interpretation is different and the code is from myself.

Community
  • 1
  • 1
A.H.
  • 63,967
  • 15
  • 92
  • 126
  • 1
    Technically the example with java.util.concurrent, is NOT a spurious wakeup. The Condition object and the real "condition" (where you check the itemsReady) are not related. – Ustaman Sangat Jun 13 '12 at 16:59
  • 1
    For the second example, One and Two would both compete for the lock, it just happens that One acquires the lock first (but this is NOT guaranteed). If Two acquired the lock first, and then One acquired it next, One will say "One: Spurious Wake..." - but this again is NOT a spurious wake up. – Ustaman Sangat Jun 13 '12 at 17:11
  • @UstamanSangat: As I wrote: Each level in the complete stack does not define what "spurious" is but hands it up to the next level. Therefore for the programmer using `Condition`, `Lock` and the "real condition" it _is_ spurious. Regarding `Condition` and "real condition": AFAIK this is the usual way frameworks are written and used in this realm. – A.H. Jun 13 '12 at 18:14
  • 1
    I agree with @UstamanSangat - certainly in the wait / notify example, there is a definite notify causing the wakeup. By contrast, the javadoc for Object describes "spurious wakeups" as wakeups that happen without any thread doing a notify or notifyAll at all. – Stephen C Aug 31 '12 at 00:43
3

Original question you've refered (as far, as wikipedia article) says that spurious wakeups happens in linux implementation of pthread, as side effect of process being signalled. From your question it seems to me that you missed up "signal" (which is linux inter-process communication method) with Object.notify() (which is java internal inter-thread communication method).

If you want to observe spurious wakeup -- you must run your java program and try to send it some signal.

BegemoT
  • 3,776
  • 1
  • 24
  • 30
2

I tried a simple test on Linux, by sending a simple Java process signals (such as QUIT, STOP, CONT, etc.). These did not seem to cause a spurious wakeup.

So (at least to me) it's still not clear under what conditions a Linux signal will cause a spurious wakeup in Java.

Archie
  • 4,959
  • 1
  • 30
  • 36
  • Yes, I've tried such tests too -- seems, like it is only the possibility, but not the rule, as it may seems from original post... Do not have any ideas -- just may be to vary CPUs count? May be only some threads experience wakeups on process being signalled? – BegemoT Jul 20 '11 at 12:11
1

I found a reproducer that forces spurious wakeups in Java bug 6454029. It starts up 30, 60, and then 100 pairs of waiters/notifiers and causes them to wait and notify a specified number of times. It uses standard Object.wait() and Object.notify() rather than the higher-level Lock and Condition objects. I've managed to use it to cause spurious wakeups to occur on my linux 64 bit machine with the argument value of 1000000 with both java 1.8.0-b132 and 1.6.0_45. Note that the original filer was complaining about Windows XP, so presumably this works on at least one flavor of windows as well.

Mark Winterrowd
  • 101
  • 1
  • 3
0

The amount of spurious wake-ups is directly proportional to the amount of processor cores in your system.

On a system with 24+ cores, it should be easy to encounter spurious wakeups. (Some bloggers would go as far to claim that roughly 40% of their waits are interrupted on those systems. But there surely are other factors to consider in the equation, making it hard to put a number on it.).

bvdb
  • 22,839
  • 10
  • 110
  • 123
0

AFAIK, Sun's JVM uses "green threads", also known as user-level threads. This means that JVM threads and kernel threads don't really have to map 1-to-1. Therefore, unless the specification says so, I don't see why the JVM would conform with the POSIX behavior.

So, even though the specification refers the possibility of spurious wake-ups, it should be hard build a deterministic test that causes one. Considering that the kernel threads running inside the JVM wake-up upon signal, how many green threads will you be waking up? One? Ten? None? Who knows.

João Fernandes
  • 1,101
  • 5
  • 11
  • 4
    *AFAIK, Sun's JVM uses "green threads"*, around 13 years ago yes. – bestsss Jul 24 '11 at 22:30
  • 1
    AFAIK, green threads was used in early implementations of Sun's JVM years ago -- and support for green threads was thrown away. Current commodity JVMs does not use it – BegemoT Jul 25 '11 at 09:41
  • @BegemoT, correct, green threads were use for sun solaris many years ago. – bestsss Jul 25 '11 at 12:11
  • 1
    There goes one of the myths I believed in. Thank you guys! – João Fernandes Jul 25 '11 at 12:37
  • If a java thread is no different from a green thread, then this won't make sense but maybe peculiar implementations like Azul might still use it... U can bind a platform thread (spawned using JNI) to a Thread object. – Ustaman Sangat Jun 13 '12 at 17:22