Solution (source code)

= Solution

Use one <monitor> to protect both the occupied flag and the slot. `Option` supplies an empty marker without confusing an empty slot with a valid `null` payload.

``
class MonitorMemory[T] extends Memory[T] {
  private var slot: Option[T] = None
  def write(msg: T): Unit = synchronized {
    while (slot.nonEmpty) wait()
    slot = Some(msg)
    notifyAll()
  }
  def read: T = synchronized {
    while (slot.isEmpty) wait()
    val result = slot.get
    slot = None
    notifyAll()
    result
  }
}
``

A writer changes empty to full while holding the <monitor>; a reader changes full to empty while holding the same <monitor>. The corresponding successful assignment or removal is its <linearization point>. No second writer can overwrite a full slot, and no two readers can remove one value. Rechecking in a `while` handles <spurious wakeups> and competition after notification.

There are two different waiting predicates on the same <monitor>: writers need empty, readers need full. A single arbitrary `notify` could wake a caller of the wrong kind. For example, after a reader empties the slot, waking another reader leaves it waiting again while a writer remains asleep, potentially stranding the computation. `notifyAll` prevents that <lost wake-up> pattern by allowing every waiter to recheck. Thus,
$$
\boxed{\text{one protected slot, two while-guarded waits, and notifyAll after either state change}.}
$$
With many users, each change wakes numerous <software threads> even though at most one can use that new slot state. Most reacquire the <monitor>, find their predicate false and sleep again. This <thundering herd> wastes <context switches> and lock acquisitions. It also supplies no fairness or arrival-order guarantee.