Condivisione Risorse tra threads - Prof-Matteo-Palitto-JCMaxwell/MultiThreading GitHub Wiki
Condivisione risorse e comunicazione tra Threads.
Come visto e spiegato nel paragrafo "variabili" del programma TicTac, l'uso delle variabili STATIC e' altamente sconsigliato per l'eventualita' dei conflitti tra i vari threads.
Tutti voi, non avendo di meglio da usare, avete GIUSTAMENTE usato una variabile STATIC condivisa da i 3 threads per lo svolgimento dell'Esercizio 1.
Se avesste eseguito il codice mote volte sarebbe capitato che il risultato del punteggio, qualche volta, non fosse corretto per lo stesso motivo visto sopra.
Il problema sta nel fatto che non c'e' un accesso controllato alla variabile condivisa... allo stesso modo di un incrocio stradale senza semafori e senza segnali: tutte le macchine passano nell'incrocio (risorsa condivisa tra auto che percorrono direzioni diverse), e prima o poi avviene l'incidente...
Per il problema dell'incrocio stradale, la soluzione e' aggiungere il semaforo.
Per il problema della variabile codivisa la soluzione e' il semaforo!!!
In alcuni linguaggi di programmazione vengono chiamati SEMAFORI, per quanto riguarda JAVA vengono chiamati MONITOR.
I MONITORs sono OGGETTI che mettono a disposizione alcune delle loro variabili ad altri OGGETTI che "vivono" all'interno di THREADs.
L'accesso alle variabili condivise dal MONITOR, i vari OGGETTI nei THREADs, dovranno usare solo ESCLUSVAMENTE i METODI messi a disposizione dal monitor.
I metodi del MONITOR che danno accesso alle variabili condivise saranno dette CRITICHE e saranno contraddistinte dalla parola-chiave SYNCHRONIZED.
La parola SYNCRONIZED chiude l'accesso alla variabile condivisa agli altri THREADs che vogliono usare la stessa risorsa MENTRE IN USO da un THREAD.
Vediamo come si sarebbe dovuto svolgere l'Esercizio 1 con l'uso del MONITOR:
Sostituisco la variabile STATIC che memorizza l'ultimo THREAD che scrive sullo schermo con un MONITOR.
In questo caso la risorsa condivisa e' lo schermo, perche' vorremmo che il punteggio fosse incrementato quando TOE viene scritto sullo schermo subito dopo TAC.
Qunindi possiamo creare una CLASSE MONITOR chiamata "Schermi" in cui c'e' una variabile che memorizza l'ultimo thread che ha scritto sullo schermo.
NOTA: il metodo CRITICO "scrivi" quando chiamato da un THREAD non puo' essere interrotto per la presenza della parola SYNCHRONIZED
// Classe per l'oggetto MONITOR
class Schermi {
String ultimoTHREAD = ""; // ultimo thread che ha scritto sullo schermo
int punteggio = 0; // anche punteggio viene condiviso dai threads
public int punteggio() { // fornisce il punteggio
return this.punteggio;
}
public synchronized void scrivi(String thread, String msg) {
int casuale=100+(int)(Math.random()*300); //numero casuale tra 100 e 300
// msg += ": " + casuale + " :";
if( thread.equals("TOE") && ultimoTHREAD.equals("TAC")) {
punteggio++;
msg += " <----------------";
}
try {
TimeUnit.MILLISECONDS.sleep(casuale); //casuale ora diventa un numero rappresentante il tempo il MILLISECONDI
} catch (InterruptedException e) {} //Richiamo eccezione this.ultimoTHREAD = thread;
System.out.println(msg);
ultimoTHREAD = thread;
}
}
L'output del programma "TicTacToe"
Main Thread iniziata...
<TAC> TAC: 10
<TIC> TIC: 10
<TOE> TOE: 10
<TAC> TAC: 9
<TOE> TOE: 9 <----------------
<TIC> TIC: 9
<TOE> TOE: 8
<TAC> TAC: 8
<TIC> TIC: 8
<TAC> TAC: 7
<TOE> TOE: 7 <----------------
<TIC> TIC: 7
<TIC> TIC: 6
<TAC> TAC: 6
<TOE> TOE: 6 <----------------
<TOE> TOE: 5
<TIC> TIC: 5
<TAC> TAC: 5
<TAC> TAC: 4
<TIC> TIC: 4
<TOE> TOE: 4
<TAC> TAC: 3
<TOE> TOE: 3 <----------------
<TIC> TIC: 3
<TAC> TAC: 2
<TOE> TOE: 2 <----------------
<TIC> TIC: 2
<TAC> TAC: 1
<TOE> TOE: 1 <----------------
Main THREAD terminata. Punteggio: 6
<TIC> TIC: 1
output del programma TicTacToe senza la parola chiave SYNCHRONIZED
Main Thread iniziata...
<TAC> TAC: 10: 206 :
<TIC> TIC: 10: 329 :
<TOE> TOE: 10: 345 :
<TAC> TAC: 9: 192 :
<TIC> TIC: 9: 242 :
<TOE> TOE: 9: 265 :
<TOE> TOE: 8: 170 :
<TAC> TAC: 8: 370 :
<TIC> TIC: 8: 235 :
<TAC> TAC: 7: 160 :
<TIC> TIC: 7: 136 :
<TOE> TOE: 7: 388 :
<TAC> TAC: 6: 244 :
<TIC> TIC: 6: 329 :
<TOE> TOE: 6: 210 :
<TIC> TIC: 5: 104 :
<TAC> TAC: 5: 350 :
<TOE> TOE: 5: 187 :
<TIC> TIC: 4: 308 :
<TAC> TAC: 4: 353 :
<TOE> TOE: 4: 388 :
<TIC> TIC: 3: 170 :
<TOE> TOE: 3: 174 :
<TAC> TAC: 3: 244 :
<TIC> TIC: 2: 317 :
<TOE> TOE: 2: 118 : <----------------
<TAC> TAC: 2: 330 :
<TIC> TIC: 1: 166 :
<TOE> TOE: 1: 352 : <----------------
Main THREAD terminata. Punteggio: 2
<TAC> TAC: 1: 329 :
Come potete notare rimuovendo la parola SYNCHRONIZED il programma non funziona piu'.