A condition variable is always associated with some kind of
lock; this can be passed in or one will be created by default.
(Passing one in is useful when several condition variables must
share the same lock.) A condition variable has acquire() and
release() methods that call the corresponding methods of the
associated lock. It also has a wait() method, and notify() and
notifyAll() methods. These three must only be called when the
calling thread has acquired the lock. The wait() method releases
the lock, and then blocks until it is awakened by a notify() or
notifyAll() call for the same condition variable in another
thread. Once awakened, it re-acquires the lock and returns. It
is also possible to specify a timeout. The notify() method wakes
up one of the threads waiting for the condition variable, if any
are waiting. The notifyAll() method wakes up all threads waiting
for the condition variable. Note: the notify() and notifyAll()
methods don't release the lock; this means that the thread or
threads awakened w