Memra

Coordination: wait/notify, suspend/resume, interrupts

Guarded blocks with wait/notify, cooperative suspend/resume, interrupt() and join() — and why Thread.suspend() is deprecated.

Guarded blocks: waiting for a condition

Sometimes a thread must wait until another thread changes shared state — a consumer must wait for the producer. Busy-waiting in a while (!ready) {} loop wastes the CPU. The cooperative tools are Object.wait(), notify(), and notifyAll(). They are methods on Object and must be called while holding that object's monitor (inside a synchronized block on the same object), or you get IllegalMonitorStateException.

- wait() releases the lock and parks the thread until it is notified. - notify() wakes one waiting thread; notifyAll() wakes all of them. The woken thread must re-acquire the lock before returning from wait().

The canonical guarded block always waits in a while loop, never an if, to defend against *spurious wakeups* and stale conditions:

synchronized (lock) {
    while (!ready) {        // while, NOT if
        lock.wait();         // releases lock, sleeps until notified
    }
    // ... condition is now true; act on it ...
}

The notifying side mutates the state and signals while holding the same lock:

synchronized (lock) {
    ready = true;
    lock.notifyAll();   // wake the waiters
}

Cooperative suspend/resume — the Greenhouse Part 2 pattern

The project must suspend and resume a whole collection of running event threads. The wrong way is the deprecated Thread.suspend() / Thread.resume(): suspend() freezes a thread *without releasing its locks*, so any thread needing those locks blocks forever — a classic deadlock, which is exactly why those methods are deprecated.

The correct, cooperative pattern is a guarded block driven by a flag: the thread checks a suspended flag at a safe point and wait()s while it is set; a resume() clears the flag and notifyAll()s.

class SuspendableEvent implements Runnable {
    private boolean suspended = false;
    private final Object monitor = new Object();

    public void run() {
        while (true) {
            synchronized (monitor) {
                while (suspended) {     // park at a safe point
                    try { monitor.wait(); }
                    catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        return;
                    }
                }
            }
            doOneStep();
        }
    }
    public void suspend() { synchronized (monitor) { suspended = true; } }
    public void resume() {
        synchronized (monitor) { suspended = false; monitor.notifyAll(); }
    }
}

interrupt() and join()

interrupt() is the polite way to ask a thread to stop. It sets the thread's *interrupt status*; a thread blocked in wait(), sleep(), or join() throws InterruptedException so it can clean up and exit. A compute-bound thread should poll Thread.currentThread().isInterrupted() and bail out. The idiom on catching InterruptedException is to *restore* the flag (Thread.currentThread().interrupt()) unless you are the thread's top level, so callers can see it.

join() makes one thread wait for another to finish: t.join() blocks the caller until t terminates — the standard way to wait for worker threads before reading their results.

NORMAL ~/memra/learn/comp-308/coordination-wait-notify-interrupts utf-8 LF