Przykład

public static void main( String[] args ) {
Lock lock = new Lock();
final Consumer consumer1 = new Consumer( lock, 1 );
final Consumer consumer2 = new Consumer( lock, 2 );
final Producer producer = new Producer( lock );

(new Thread( new Runnable() {
public void run() {
consumer1.consume();
}
})).start();

(new Thread( new Runnable() {
public void run() {
consumer2.consume();
}
})).start();

(new Thread( new Runnable() {
public void run() {
producer.produce();
}
})).start();
}

public static final class Lock {
public Lock() {
super();
lock();
}
public boolean isAvailable() {
return available;
}
public void lock() {
available = false;
}
public void unlock() {
available = true;
}
private boolean available = false;
}

public static final class Consumer {
public Consumer( Lock lock, int id ) {
this .lock = lock;
this .id = id;
}

public void consume() {
System.out.println( "Consumer " + id + ": wywołano metodę consume" ); //$NON-NLS-1$ //$NON-NLS-2$
synchronized ( lock ) {
while ( !lock.isAvailable() ) {
System.out.println( "Consumer" + id + ": oczekiwanie..." ); //$NON-NLS-1$ //$NON-NLS-2$
try {
lock.wait();
} catch (InterruptedException e) {}
}
}
System.out.println( "Consumer" + id + ": zamykanie" ); //$NON-NLS-1$ //$NON-NLS-2$
}

private Lock lock;
private int id;
}

public static final class Producer {
public Producer( Lock lock ) {
this .lock = lock;
}
public void produce() {
System.out.println( "Producer: wywołano metodę produce" ); //$NON-NLS-1$
System.out.println( "Producer: odblokowywanie..." ); //$NON-NLS-1$
synchronized ( lock ) {
lock.unlock();
lock.notify();
}
System.out.println( "Producer: zamykanie" ); //$NON-NLS-1$
}
private Lock lock;
}



Rozwiązanie
Zamiast metody notify() wywołaj metodę notifyAll().

public static void main( String[] args ) {
Lock lock = new Lock();
final Consumer consumer1 = new Consumer( lock, 1 );
final Consumer consumer2 = new Consumer( lock, 2 );
final Producer producer = new Producer( lock );

(new Thread( new Runnable() {
public void run() {
consumer1.consume();
}
})).start();

(new Thread( new Runnable() {
public void run() {
consumer2.consume();
}
})).start();

(new Thread( new Runnable() {
public void run() {
producer.produce();
}
})).start();
}

public static final class Lock {
public Lock() {
super();
lock();
}
public boolean isAvailable() {
return available;
}
public void lock() {
available = false;
}
public void unlock() {
available = true;
}
private boolean available = false;
}

public static final class Consumer {
public Consumer( Lock lock, int id ) {
this .lock = lock;
this .id = id;
}

public void consume() {
System.out.println( "Consumer " + id + ": wywołano metodę consume" ); //$NON-NLS-1$ //$NON-NLS-2$
synchronized ( lock ) {
while ( !lock.isAvailable() ) {
System.out.println( "Consumer" + id + ": oczekiwanie..." ); //$NON-NLS-1$ //$NON-NLS-2$
try {
lock.wait();
} catch (InterruptedException e) {}
}
}
System.out.println( "Consumer" + id + ": zamykanie" ); //$NON-NLS-1$ //$NON-NLS-2$
}

private Lock lock;
private int id;
}

public static final class Producer {
public Producer( Lock lock ) {
this .lock = lock;
}
public void produce() {
System.out.println( "Producer: wywołano metodę produce" ); //$NON-NLS-1$
System.out.println( "Producer: odblokowywanie..." ); //$NON-NLS-1$
synchronized ( lock ) {
lock.unlock();
lock.notifyAll();
}
System.out.println( "Producer: zamykanie" ); //$NON-NLS-1$
}
private Lock lock;
}