4. Synchronizing Threads

class Producer extends Thread {
    public void run() {
        for (int i = 0; i < 10; i++) {
            cubbyhole.put(i);
            System.out.println("Producer #" + this.number + " put: " + i);
            try {
                sleep((int)(Math.random() * 100));
            } catch (InterruptedException e){}
        }
    }
}

The Consumer consumes all integers from the CubbyHole as quickly as they become available.

class Consumer extends Thread {
    public void run() {
        int value = 0;
        for (int i = 0; i < 10; i++) {
            value = cubbyhole.get();
            System.out.println("Consumer #" + this.number + " got: " + value);
        }
    }
}

4.1.1. Two outcomes

Producer is quicker than the Consumer:

. . .
Consumer #1 got: 3
Producer #1 put: 4
Producer #1 put: 5
Consumer #1 got: 5
. . .

Consumer is quicker than the Producer:

. . .
Producer #1 put: 4
Consumer #1 got: 4
Consumer #1 got: 4
Producer #1 put: 5
. . .

Audio in Portuguese

4.2. Monitors

Definition: A monitor is associated with a specific data item and functions as a lock on that data.

  • When a thread holds the monitor for some data item, other threads are locked out and cannot inspect or modify the data.

  • A unique monitor is associated with every object that has a synchronized method.

class CubbyHole {
    private int contents;
    private boolean available = false;

    public synchronized int get() {
        while (available == false) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        available = false;
        notify();
        return contents;
    }

    public synchronized void put(int value) {
        while (available == true) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        contents = value;
        available = true;
        notify();
    }
}

4.2.1. Control

Lock: The thread that called a synchronized method acquires the monitor for the object whose method has been called.

Object state: No other threads can call a synchronized method on the same object.

Unlock: When the synchronized method returns, the thread releases the monitor thereby unlocking the object.

Audio in Portuguese

4.3.1. The wait() method

The wait() method causes the current thread to:

  1. Wait until another thread notifies it of a condition change.

  2. Release the monitor for the object.

public synchronized int get() {
    while (available == false) {
        try {
            wait();          // waits for notify() call from Producer
        } catch (InterruptedException e) {
        }
    }
    available = false;
    notify();
    return contents;
}

Other versions:

wait(long timeout) 
wait(long timeout, int nanos) 

4.3.2. The notify() method

The notify() method chooses one thread that is waiting on the monitor held by the current thread and wakes it up.

[Note]Note

The Java runtime system makes no commitments or guarantees about which thread will be chosen.

public synchronized int get() {
    while (available == false) {
        try {
            wait();
        } catch (InterruptedException e) {
        }
    }
    available = false;
    notify();           // notifies Producer
    return contents;
}

notifyAll():

  1. It wakes up all the threads waiting on the same monitor.

  2. The awakened threads compete for the monitor.

  3. One thread gets the monitor and the others go back to waiting.

Audio in Portuguese