The JavaTM Tutorial

| Start of Tutorial > Start of Trail > Start of Lesson | Search

Trail: Essential Java Classes
Lesson: Doing Two or More Tasks At Once: Threads

## Using the notifyAll and wait Methods

> The `CubbyHole` stores its value in a private member variable called `contents`. `CubbyHole` has another private member variable, `available`, that is a `boolean`. `available` is `true` when the value has just been put but not yet gotten and is false when the value has been gotten but not yet put. So, here's one possible implementation for the `put` and `get` methods:

> >     public synchronized int get() {    // won't work!
> >         if (available == true) {
> >             available = false;
> >             return contents;
> >         }
> >     }
> >     public synchronized int put(int value) {    // won't work!
> >         if (available == false) {
> >             available = true;
> >             contents = value;
> >         }
> >     }

> As implemented, these two methods won't work. Look at the `get` method. What happens if the `Producer` hasn't put anything in the `CubbyHole` and `available` isn't `true`? `get` does nothing. Similarly, if the `Producer` calls `put` before the `Consumer` got the value, `put` doesn't do anything.

> You really want the `Consumer` to wait until the `Producer` puts something in the `CubbyHole` and the `Producer` must notify the `Consumer` when it's done so. Similarly, the `Producer` must wait until the `Consumer` takes a value (and notifies the `Producer` of its activities) before replacing it with a new value. The two threads must coordinate more fully and can use `Object`'s `wait` and `notifyAll` methods to do so.

> Here are the new implementations of `get` and `put` that wait on and notify each other of their activities:

> >     public synchronized int get() {
> >         while (available == false) {
> >             try {
> >                 // wait for Producer to put value
> >                 wait();
> >             } catch (InterruptedException e) {
> >             }
> >         }
> >         available = false;
> >         // notify Producer that value has been retrieved
> >         notifyAll();
> >         return contents;
> >     }
> >     public synchronized void put(int value) {
> >         while (available == true) {
> >             try {
> >                 // wait for Consumer to get value
> >                 wait();
> >             } catch (InterruptedException e) {
> >             }
> >         }
> >         contents = value;
> >         available = true;
> >         // notify Consumer that value has been set
> >         notifyAll();
> >     }

> The code in the `get` method loops until the `Producer` has produced a new value. Each time through the loop, `get` calls the `wait` method. The `wait` method relinquishes the lock held by the `Consumer` on the `CubbyHole` (thereby allowing the `Producer` to get the lock and update the `CubbyHole`) and then waits for notification from the `Producer`. When the `Producer` puts something in the `CubbyHole`, it notifies the `Consumer` by calling `notifyAll`. The `Consumer` then comes out of the wait state, `available` is now `true`, the loop exits, and the `get` method returns the value in the `CubbyHole`.

> The `put` method works in a similar fashion, waiting for the `Consumer` thread to consume the current value before allowing the `Producer` to produce a new one.

> The `notifyAll` method wakes up all threads waiting on the object in question (in this case, the `CubbyHole`). The awakened threads compete for the lock. One thread gets it, and the others go back to waiting. The `Object` class also defines the notify method, which arbitrarily wakes up one of the threads waiting on this object.

> The `Object` class contains not only the version of `wait` that is used in the producer/consumer example and which waits indefinitely for notification, but also two other versions of the `wait` method:

> wait(long timeout)
>   Waits for notification or until the `timeout` period has elapsed. `timeout` is measured in milliseconds.
> wait(long timeout, int nanos)
>   Waits for notification or until `timeout` milliseconds plus `nanos` nanoseconds have elapsed.

> > Note: Besides using these timed `wait` methods to synchronize threads, you also can use them in place of `sleep`. Both `wait` and `sleep` delay for the requested amount of time, but you can easily wake up `wait` with a notify but a sleeping thread cannot be awoken prematurely. This doesn't matter too much for threads that don't sleep for long, but it could be important for threads that sleep for minutes at a time.

| Start of Tutorial > Start of Trail > Start of Lesson | Search