starting execution of its method. Note that without this mutual exclusion, in the present example, two threads could cause money to be lost or gained for no reason. For example, two threads withdrawing 1000 from the account could both return true, while causing the balance to drop by only 1000, as follows: first, both threads fetch the current balance, find it greater than 1000, and subtract 1000 from it; then, both threads store the balance and return. The syntactic sugar "monitor class" in the above example is implementing the following basic representation of the code, by wrapping each function's execution in mutexes: class Account { private lock myLock private int balance := 0 invariant balance >= 0 public method boolean withdraw(int amount) precondition amount >= 0 { myLock.acquire() try { if balance < amount { return false } else { balance := balance - amount return true } } finally { myLock.release() } } public method deposit(int amount) precondition amount >= 0 { myLock.acquire() try { balance := balance + amount } finally { myLock.release() } } } Condition variables Problem statement For many applications, mutual exclusion is not enough. Threads attempting an operation may need to wait until some condition holds true. A busy waiting loop while not ( ) do skip will not work, as mutual exclusion will prevent any other thread from entering the monitor to make the condition true. Other "solutions" exist such as having a loop that unlocks the monitor, waits a certain amount of time, locks the monitor and checks for the condition . Theoretically, it works and will not deadlock, but issues arise. It is hard to decide an appropriate amount of waiting time: too small and the thread will hog the CPU, too big and it will be apparently unresponsive. What is needed is a way to signal the thread when the condition is true (or could be true). Case study: classic bounded producer/consumer problem A classic concurrency problem is that of the bounded producer/consumer, in which there is a queue or ring buffer of tasks with a maximum size, with one or more threads being "producer" threads that add tasks to the queue, and one or more other threads being "consumer" threads that take tasks out of the queue. The queue is assumed to be non–thread-safe itself, and it can be empty, full, or between empty and full. Whenever the queue