Another bugfix: switch from notify() to notifyAll() — always wake up all waiting threads.
Instead of non-deterministically notifying one thread, we now notify all waiting threads. This is the standard fix for the lost-wakeup problem.
With notify(), the JVM might wake up a thread that cannot make progress (e.g., waking a producer when the buffer is already full). That thread goes back to waiting, and the actual thread that could make progress is never woken — leading to deadlock.
notifyAll() ensures every waiting thread gets a chance to check whether it can proceed.
As a bonus exercise, check if it is necessary to notify all waiting threads in both Put and Get.
Note that this is the proposed solution to the bug in Challenge 14 of the c2 extreme programming wiki. To the best of my knowledge, not a single comment mentions that just one notifyAll suffices. Neither does anybody mention a more elegant fix that has no performance implications (see next step).