The following steps lead us to deadlock. Let's set limit to 1 to keep the example brief.
- E1 enqueues an item.
- E2 attempts enqueue - checks wait loop - already full - waits
E3 attempts enqueue - checks wait loop - already full - waits
D1 attempts dequeue - and is executing synchronized block
- D2 attempts dequeue - blocks on entry to the (synchronized) block - due to D1
D3 attempts dequeue - blocks on entry to the (synchronized) block - due to D1
D1 is executing enqueue - gets the item, calls notify, exits method
- The notify happens to wake up E2 (i.e. "any waiting thread")
- BUT, D2 enters sync block before E2 can (E2 must reacquire the lock), so E2 blocks on entry to the enqueue sync block
- D2 checks wait loop, no more items in queue, so waits
D3 enters block after D2, but before E2, checks wait loop, no more items in queue, so waits
Now there is E3, D2, and D3 waiting!
Finally E2 acquires the lock, enqueues an item, calls notify, exits method
E2's notification wakes E3 (remember any thread can be woken)
- E3 checks the wait loop condition, there is already an item in the queue, so waits.
- NO MORE THREADS TO CALL NOTIFY and THREE THREADS PERMANENTLY SUSPENDED!
SOLUTION: Replace notify with notifyAll