Andbin ho aggiunto all'interno dei metodi run() del Produttore e del Consumatore due blocchi synchronized, sincronizzati sull'oggetto buffer, e sembra che ora funzioni tutto bene 
codice:
public class Consumatore implements Runnable {
private Buffer<Paziente> buffer;
private int ritardo;
public Consumatore (Buffer<Paziente> buffer, int ritardo)
{
this.ritardo=ritardo;
this.buffer=buffer;
}
public void run() {
int i;
for(i=0; true; i++)
{
synchronized(buffer)
{
Paziente p = buffer.preleva();
System.out.println ("Prelevato: " + p + "\n" + buffer.getSize());
}
try
{
Thread.sleep(ritardo);
}
catch(InterruptedException e){}
}
}
}
codice:
public class Produttore implements Runnable{
private Buffer<Paziente> buffer;
private int ritardo;
public Produttore (Buffer<Paziente> buffer, int ritardo)
{
this.buffer=buffer;
this.ritardo=ritardo;
}
public void run() {
int i;
for(i=0; true; i++)
{
synchronized(buffer)
{
Paziente p = new Paziente("Nome " + i, "Cognome " + i);
buffer.aggiungi(p);
System.out.println("Inserito: " + p + buffer.getSize());
}
try
{
Thread.sleep(ritardo);
}
catch(InterruptedException e){}
}
}
}
Ho provato tutte le possibili combinazioni, velocità uguali del prod. e cons., diverse ecc..... e con qualsiasi dimensione della struttura dati, e l'output è come ci si aspettasse, quindi non ci sono più problemi di stampe di pazienti prima delle stampe dell'arrivo, e/o viceversa.
Grazie 1000 Andbin