2

I have read many posts on this. This answer https://stackoverflow.com/a/6701060/2359945 claimed a 100 bounty by suggesting to test the interrupted flag.

I tested this, and it does not work for me. So, the question remains, how do I detect a spurious wakeup, or is it not possible? Thank you.

class TestSpuriousWakeup {
  static Thread t1, tInterrupt, tNotify;

  // spawn one thread that will be interrupted and be notified
  // spawn one thread that will interrupt
  // spawn one thread that will notify
  public static void main(String[] args) {
    System.out.println("*** main Starting");
    initThreads();

    try {
      t1.start();

      Thread.sleep(2000);
      tNotify.start();
      tNotify.join();

      Thread.sleep(2000);
      tInterrupt.start();
      tInterrupt.join();

      t1.join();
    } catch (InterruptedException e) {
      System.out.println("*** Unexpected interrupt in main");
    }

    System.out.println("*** main Ended.");
  }

  private static void initThreads() {
    t1 = new Thread() {
      @Override
      public void run() {
        System.out.println("ThreadInterruptMe Started ...");
        boolean stop = false;
        Thread.interrupted(); // clear the interrupted flag
        while (!stop) {
          try {
            System.out.println("ThreadInterruptMe Sleeping 5000ms ...");
            Thread.sleep(5000);
          } catch (InterruptedException e) {
            System.out.println("ThreadInterruptMe InterruptedException e!");
            System.out.println("ThreadInterruptMe e.getCause => " + e.getCause());
            System.out.println("ThreadInterruptMe e.getLocalizedMessage => " + e.getLocalizedMessage());
            stop = Thread.interrupted();

            if (stop) {
              System.out.println("ThreadInterruptMe was INTERRUPTED because Thread.interrupted() is true"); // never happens
            } else {
              System.out.println("ThreadInterruptMe was NOTIFIED because Thread.interrupted() is false"); // always happens
            }
          } finally {
            Thread.interrupted(); // clear the interrupted flag
            System.out.println("ThreadInterruptMe InterruptedException finally");
          }
        }
        System.out.println("ThreadInterruptMe Ended.");
      }
    };

    tInterrupt = new Thread() {
      @Override
      public void run() {
        System.out.println("  ThreadInterruptYou Started ... interrupting now!");
        t1.interrupt();
        System.out.println("  ThreadInterruptYou Ended.");
      }
    };

    tNotify = new Thread() {
      @Override
      public void run() {
        System.out.println("    ThreadNotifyYou Started ... notifying now!");
        t1.interrupt();
        System.out.println("    ThreadNotifyYou Ended.");
      }
    };
  }
}

Output:

*** main Starting
ThreadInterruptMe Started ...
ThreadInterruptMe Sleeping 5000ms ...
    ThreadNotifyYou Started ... notifying now!
ThreadInterruptMe InterruptedException e!
    ThreadNotifyYou Ended.
ThreadInterruptMe e.getCause => null
ThreadInterruptMe e.getLocalizedMessage => sleep interrupted
ThreadInterruptMe was NOTIFIED because Thread.interrupted() is false
ThreadInterruptMe InterruptedException finally
ThreadInterruptMe Sleeping 5000ms ...
  ThreadInterruptYou Started ... interrupting now!
ThreadInterruptMe InterruptedException e!
ThreadInterruptMe e.getCause => null
ThreadInterruptMe e.getLocalizedMessage => sleep interrupted
ThreadInterruptMe was NOTIFIED because Thread.interrupted() is false
ThreadInterruptMe InterruptedException finally
ThreadInterruptMe Sleeping 5000ms ...
  ThreadInterruptYou Ended.
ThreadInterruptMe InterruptedException finally
ThreadInterruptMe Sleeping 5000ms ...
ThreadInterruptMe InterruptedException finally
ThreadInterruptMe Sleeping 5000ms ...

<infinite loop>
Community
  • 1
  • 1
Razzle Shazl
  • 1,287
  • 1
  • 8
  • 20

2 Answers2

11

What spurious wakeups are not

sleep() is not subject to spurious wakeups. The low-level system call it uses to sleep may be, but Java takes care of this detail for you, re-entering the system call if it's woken up prematurely. As a user you are not exposed to spurious wakeups.

Spurious wakeups are also unrelated to thread interruption. That is a separate tool. Threads are never "spuriously interrupted". If your thread is interrupted, that means somebody somewhere called Thread.interrupt() on your thread. Find that code and you will have the culprit.

What spurious wakeups are

If you want to test spurious wakeups, run tests with Object.wait() instead, since that's the classic method that suffers from them.

The naïve way of using wait() is to simply call it, expecting that it will only return when some other thread calls notify(). For example, a message sending loop might be:

for (;;) {
    synchronized (monitor) {
        if (queue.isEmpty()) {  // incorrect
            monitor.wait();
        }
    }

    send(queue.remove());
}

This will fail if wait() spuriously wakes up without a message having been added to the queue. The solution is to add a loop around the wait() to verify the condition every time the thread is woken up.

for (;;) {
    synchronized (monitor) {
        while (queue.isEmpty()) {  // correct
            monitor.wait();
        }
    }

    send(queue.remove());
}

The simplest way to simulate a spurious wakeup, then, is to simply call notify() without changing the loop condition.

synchronized (monitor) {
    monitor.notify();
}

This will have the exact same effect on the thread performing wait() as if it encountered a spurious wakeup. The incorrect code using if won't realize the queue is still empty and will crash. The correct code using while will re-check the condition and safely re-enter the wait() call.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • Thanks, you seemed to have nailed it. I particularly enjoyed learning about the java libraries that handled reinserting a thread into sleep call in case at the system level it spuriously triggered a wakeup. Marking accepted. – Razzle Shazl Jun 05 '15 at 23:10
  • do you have any citation regarding your claim on `sleep`? as far as i am concerned, there is nowhere it's mentioned that `sleep` is not waken up by spurious wakeup. and does it cover all the OSes? wondering if you can share more – Jason Hu Nov 01 '16 at 22:17
  • There doesn't need to be documentation of a negative. It's the other way around. `sleep()` isn't documented as being subject to spurious wakeups, therefore it isn't subject to them. If it were, there'd be some mention of the fact that `sleep()` could delay for less than the requested amount. `Object.wait()`, on the other hand, does have such a note: "A thread can also wake up without being notified, interrupted, or timing out, a so-called *spurious wakeup*." – John Kugelman Nov 02 '16 at 03:24
  • 1
    Are there any guarantees to retrieve a non-stale result when checking the condition after a spurious wakeup? – user1072706 Aug 31 '17 at 22:34
  • While this is a useful answer for delving into the behavior of spurious wakeup, I have marked the answer from @David as correct as he answered my original question of how to detect a spurious wakeup. – Razzle Shazl Jun 25 '18 at 21:14
2

You detect a spurious wakeup by re-testing the predicate.

A wakeup is spurious if there is no reason for the wakeup. A wakeup is not spurious if some other thread intentionally woke you.

Or, to put it even more simply: If the thing you were waiting for hasn't happened, the wakeup was spurious. If the thing you were waiting for has happened, the wakeup was not spurious. You have to be able to check whether the thing you were waiting or has happened or not -- otherwise, how did you know you had to wait for it in the first place?

So before a thread intentionally wakes you, have it set some synchronized variable that you check when you wake up. If that variable is set, then the wakeup was not spurious, and you clear the flag. If it is not set, then the wakeup was spuroius, and you typically ignore the wakeup.

So, the flow goes as follows:

To wake/signal/interrupt at thread:

  1. Acquire a lock or enter a synchronized block.
  2. Set the boolean predicate to true.
  3. Wake the thread.
  4. Release the lock or exit the synchronized block.
    (If desired, the order of 3 and 4 can be swapped.)

To wait for something to happen:

  1. Acquire a lock or enter a synchronized block.
  2. Set the boolean predicate to false (or check it if it was already set).
  3. Wait, releasing the lock. When woken, reacquire the lock (or re-enter a synchronized block).
  4. Check the predicate to see if the wake is spurious. If the predicate is false, go to step 3.
  5. You now know the wakeup was not spurious. Release the lock or exit the synchronized block.
David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • If I understand you correctly, given that threadA wants to interrupt threadB, you would recommend that threadA set a semaphore before interrupting threadB, then threadB should embark on testing the semaphore? Is this as an exercise or for a real system? Who would be responsible for managing that semaphore? Isn't this rather cumbersome? Could you provide some code or at least some clarification of "re-testing the predicate"? Thank you. – Razzle Shazl Jun 06 '15 at 01:53
  • No, not a semaphore, just some synchronized variable that you check when you wake up, typically a boolean. This is the normal way this is done. I'll update the answer with some details. [Here's](http://stackoverflow.com/questions/4496568/pthread-condition-loop) a classic example of avoiding spurious wakeups with condition variables in C. – David Schwartz Jun 06 '15 at 02:30
  • Marking as accepted as this answered my question on how to detect a spurious wakeup. – Razzle Shazl Jun 25 '18 at 21:17