WaitQueue (apache-cassandra API)
Date: 2018-02-12

org.apache.cassandra.utils.concurrent

## Class WaitQueue

- java.lang.Object
- - org.apache.cassandra.utils.concurrent.WaitQueue

-     public final class WaitQueue
      extends java.lang.Object

  A relatively easy to use utility for general purpose thread signalling.

  Usage on a thread awaiting a state change using a WaitQueue q is:

            while (!conditionMet())
                Signal s = q.register();
                    if (!conditionMet())    // or, perhaps more correctly, !conditionChanged()
                        s.await();
                    else
                        s.cancel();

  A signalling thread, AFTER changing the state, then calls q.signal() to wake up one, or q.signalAll() to wake up all, waiting threads.

  To understand intuitively how this class works, the idea is simply that a thread, once it considers itself incapable of making progress, registers to be awoken once that changes. Since this could have changed between checking and registering (in which case the thread that made this change would have been unable to signal it), it checks the condition again, sleeping only if it hasn't changed/still is not met.

  This thread synchronisation scheme has some advantages over Condition objects and Object.wait/notify in that no monitor acquisition is necessary and, in fact, besides the actual waiting on a signal, all operations are non-blocking. As a result consumers can never block producers, nor each other, or vice versa, from making progress. Threads that are signalled are also put into a RUNNABLE state almost simultaneously, so they can all immediately make progress without having to serially acquire the monitor/lock, reducing scheduler delay incurred.

  A few notes on utilisation:

  1. A thread will only exit await() when it has been signalled, but this does not guarantee the condition has not been altered since it was signalled, and depending on your design it is likely the outer condition will need to be checked in a loop, though this is not always the case.

  2. Each signal is single use, so must be re-registered after each await(). This is true even if it times out.

  3. If you choose not to wait on the signal (because the condition has been met before you waited on it) you must cancel() the signal if the signalling thread uses signal() to awake waiters; otherwise signals will be lost. If signalAll() is used but infrequent, and register() is frequent, cancel() should still be used to prevent the queue growing unboundedly. Similarly, if you provide a TimerContext, cancel should be used to ensure it is not erroneously counted towards wait time.

  4. Care must be taken when selecting conditionMet() to ensure we are waiting on the condition that actually indicates progress is possible. In some complex cases it may be tempting to wait on a condition that is only indicative of local progress, not progress on the task we are aiming to complete, and a race may leave us waiting for a condition to be met that we no longer need.

  5. This scheme is not fair

  6. Only the thread that calls register() may call await()

- - ### Nested Class Summary

    Nested Classes
    Modifier and Type | Class and Description
    --- | ---
    `static class` | `WaitQueue.AbstractSignal` An abstract signal implementation
    `static interface` | `WaitQueue.Signal` A Signal is a one-time-use mechanism for a thread to wait for notification that some condition state has transitioned that it may be interested in (and hence should check if it is).

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `WaitQueue()`

  - ### Method Summary

    All Methods Static Methods Instance Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `static WaitQueue.Signal` | `all(WaitQueue.Signal... signals)`
    `static WaitQueue.Signal` | `any(WaitQueue.Signal... signals)`
    `int` | `getWaiting()` Return how many threads are waiting
    `boolean` | `hasWaiters()`
    `WaitQueue.Signal` | `register()` The calling thread MUST be the thread that uses the signal
    `WaitQueue.Signal` | `register(com.codahale.metrics.Timer.Context context)` The calling thread MUST be the thread that uses the signal.
    `boolean` | `signal()` Signal one waiting thread
    `void` | `signalAll()` Signal all waiting threads

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Constructor Detail

    - #### WaitQueue

          public WaitQueue()

  - ### Method Detail

    - #### register

          public WaitQueue.Signal register()

      The calling thread MUST be the thread that uses the signal
      Returns:
        x

    - #### register

          public WaitQueue.Signal register(com.codahale.metrics.Timer.Context context)

      The calling thread MUST be the thread that uses the signal. If the Signal is waited on, context.stop() will be called when the wait times out, the Signal is signalled, or the waiting thread is interrupted.
      Returns:

    - #### signal

          public boolean signal()

      Signal one waiting thread

    - #### signalAll

          public void signalAll()

      Signal all waiting threads

    - #### hasWaiters

          public boolean hasWaiters()

    - #### getWaiting

          public int getWaiting()

      Return how many threads are waiting
      Returns:

    - #### any

          public static WaitQueue.Signal any(WaitQueue.Signal... signals)

      Parameters:
        `signals` -
      Returns:
        a signal that returns only when any of the provided signals would have returned

    - #### all

          public static WaitQueue.Signal all(WaitQueue.Signal... signals)

      Parameters:
        `signals` -
      Returns:
        a signal that returns only when all provided signals would have returned

Copyright © 2018 The Apache Software Foundation