Ecco l'esempio con la classe main di prova:

Test.java
-------
import java.util.*;

public class Test {
public static void main(String args[]) {
Buffer<Integer> b = new Buffer<Integer>(10);
new Produttore(b);
new Consumatore(b);
}
}

class Buffer<T> {
protected T element;
protected boolean flagSet = false;
public int max;

Buffer(int max) {
this.max = max;
}

synchronized T get() {
if(!flagSet) {
  try {
   wait();
  } catch(Exception e) {}
}

System.out.println("Consumato: " + element);
flagSet = false;
notify();
return element;
}

synchronized void put(T element) {
if(flagSet) {
  try {
   wait();
  } catch(Exception ex) {}
}
this.element = element;
flagSet = true;
System.out.println("Prodotto " + element);
notify();
}
}

class Produttore implements Runnable {
Buffer b;

Produttore(Buffer b) {
this.b = b;
new Thread(this).start();
}

public void run() {
int i = 0;
while(i <= b.max) {
b.put(i++);
}
}
}

class Consumatore implements Runnable {
Buffer<Integer> b;

Consumatore (Buffer b) {
this.b = b;
new Thread(this).start();
}

public void run() {
int i = 0;
while(i <= b.max) {
b.get();
}
}
}
----------