Buongiorno a tutti, chiedo aiuto su un esercizio complicato per quanto riguarda la sincronizzazione.
Spiego meglio il mio problema descrivendolo.

Un sueprmercato dispone di 3 addetti e 3 casse. Per oni cassa non sono ammesse file con più di 5 clienti. Accade spesso che un addetto debba allontanarsi dalla cassa per assistere un cliente durante la spesa ed in tal caso i clienti già in fila vengano accodati in modo ordinato nelle altre casse, dando priorità alle casse più vicine, purchè le nuove file non superino la massima lunghezza consentita.

I clienti aspetteranno, e successivamente si accoderanno in modo casuale, qualora tutte le file siano già composte da 5 clienti.

Io ho pensato di usare la politica del produttore consumatore, quindi, ho creato una classe cliente(thread), addetto(thread), supermercato(risorsa condivisa) e una classe cassa dove sono presenti solo 2 variabili una int coda e una boolean stato cassa chiusa/aperta per creare un array ad oggetti nella classe supermercato.

Posto il codice supermercato, essendo che nel cliente abbiamo un metodo paga() e nell'addetto un metodo incassa(), quindi il cliente incrementa una variabile e l'addetto decrementa tale variabile.

codice classe supermercato:

codice:
//Classe Supermercato condivisa tra tutti i thread clienti e addetti

public class Supermercato {
	
	static int MAX_CASSE;//indica il numero massimo di casse disponibili
	private int MAX_CODA;//indica la coda massima di ongni singola coda
	private Cassa casse[]; //creo un array di tipo Cassa
	
//----------------------------------------------------COSTRUTTORE----------------------------------
	public Supermercato(){
		
		MAX_CASSE=3;//inizializzazione max_casse
		MAX_CODA=5;//inizializzaziond max_coda
		casse = new Cassa[MAX_CASSE];//inizializzo l'array formato da 3 celle
		//inizializzazione casse tramite costruttore
		for(int i=0; i<casse.length; i++){
			casse[i] = new Cassa(0, true, "Cassa"+i);//inizializzo a zero la coda poi a true(aperta) la cassa e gli passo un nome
			
		}//fine for 
		
	}//fine costruttore
	
	
	
//------------------------------------------------------METODI---------------------------------------
	
//questo metodo permette la scelta della cassa migliore, quindi con minor numero di clienti in coda-----------------------------
	public String scegliCassa() {

		if( casse[0].get_coda() <= casse[1].get_coda() ){
			
			if( casse[0].get_coda() <= casse[2].get_coda() ){
				return casse[0].get_nome();
			}else
				return casse[2].get_nome();
			
		}else if(casse[1].get_coda() <= casse[2].get_coda() ){
			
			return casse[1].get_nome();
		}else 
			return casse[2].get_nome();
		
	     
	}//fine metodo scegliCassa

	
	
	
//questo metodo aggiunge un cliente alla coda, incrementando l'opportuna variabile--------------------------------------
	public synchronized void paga(){
		
		System.out.println("Il " + Thread.currentThread().getName() + " è entrato nel supermercato.");
		System.out.printf("la funzone sceltaCassa ha scelto la %s\n", scegliCassa());
		
		String cassaScelta = scegliCassa();
		
		for(int i=0; i<casse.length; i++){
			
			System.out.printf("entro nel ciclo: %d\n",i);
			//se il nome della cassa(i) è uguale al nome ritornato dal metodo scegliCassa, la coda è minore di 5, 
			// e lo stato della cassa è true(aperta) il thread si mette in coda nella cassa con minor numero di clienti(thread)
			if( casse[i].get_nome().equals(cassaScelta) && (casse[i].get_coda()<MAX_CODA) && (casse[i].get_statoCassa()==true) ){
				System.out.println("Il " + Thread.currentThread().getName() + " si mette in coda nella " + casse[i].get_nome());
				notify();//mando un signal di risveglio
				casse[i].set_coda("i");//incrementa la coda
				System.out.printf("Adesso la coda è di %d\n", casse[i].get_coda());
				break;
			}else{//altrimenti essendo che le code delle casse sono tutte piene 
				try {
					wait();//il cliente si fa una passeggiata(entra in waiting) aspettando che si liberi una delle code.
				} catch (InterruptedException e) {
					
					e.printStackTrace();
				}//fine catch
			}//fine else
			
			System.out.printf("ciclo n: %d\n",i);
		}//fine for

	}//fine metodo paga
	
	
	
	
	public synchronized void incassa(){
		
		
	}//fine metodo incassa
	
}//fine classe supermercato
l'output che viene fuori da questo primo codice è il seguente:

codice:
Il Cliente9 è entrato nel supermercato.
la funzone sceltaCassa ha scelto la Cassa0
entro nel ciclo: 0
Il Cliente9 si mette in coda nella Cassa0
Adesso la coda è di 1
Il Cliente9 ha pagato e sta uscendo.
Il Cliente2 è entrato nel supermercato.
la funzone sceltaCassa ha scelto la Cassa1
entro nel ciclo: 0
Addetto3 ha passato i prodotti e incassato.
Il Cliente7 è entrato nel supermercato.
la funzone sceltaCassa ha scelto la Cassa1
entro nel ciclo: 0
Addetto1 ha passato i prodotti e incassato.
Il Cliente1 è entrato nel supermercato.
la funzone sceltaCassa ha scelto la Cassa1
entro nel ciclo: 0
Il Cliente10 è entrato nel supermercato.
Non appena il programma parte, i primi 6 passi sono corretti.
come è possibile che il thread(cliente2) è entrato nella sezione critica neanche il tempo di eseguire il ciclo for entra un altro thread(Cliente7)? non dovrebbe mantenere il look fino a quando non ha finito di eseguire tutte le istruzioni presenti all'interno del metodo paga()?

Poi, la politica che sto utilizzando vi sembra una politica buona? avete piccoli ma grandi consigli?
Cosa sbaglio?



Grazie in anticipo...spero in un vostro aiuto...