Java: programmazione concorrente con condivisione di memoria Problemi di correttezza dovuti all’accesso concorrente di più processi ad una stessa area di memoria.Si pensi a tutte le situazioni in cui l’aggiornamento di un dato dipende dal suo valore Esempio del conto corrente bancario: Se ho i soldi posso fare il prelievo. Se pero` consento a più persone (processi) cointestatarie del conto l’accesso ai dati rischio di andare in rosso!
Caratteristiche di Java per scrivere programmi concorrenti Possibilità di generare processi usando la Classe Thread. Ogni oggetto ha un lock questo permette di rendere sequenziale l’esecuzione dei metodi di un qualunque oggetto: descrittore synchronized metodi wait e notify della classe Object.
La classe Thread La classe Thread di Java fa parte della libreria Lang (import java.lang.*;); è una sottoclasse di Object ; implementa l’interfaccia Runnable (un’interfaccia che ha un unico metodo: il metodo run); ha diversi costruttori (ne vedremo alcuni) molti metodi (ne vedremo solo alcuni tra cui il metodo run)
Per usare i Thread ci sono due possibilità Definire una classe che estende Thread e ridefinire il metodo run Definire una classe, implementazione dell’interfaccia Runnable, per cui si definisce il metodo run ed costruire un Thread passandogli tale un oggetto di tale classe. La seconda soluzione permette di definire la classe anche come sottoclasse di qualche altra classe.
Costruttori Thread() crea un nuovo Thread Thread(Runnable target) crea un nuovo Thread, passando come argomento un oggetto Runnable il cui run verrà invocato dal metodo run del thread Thread(String name) crea un nuovo Thread, con nome name Thread(Runnable target, String name) come i due precedenti
Metodi principali getName() restituisce il nome del thread join() aspetta che il thread termini run() se il thread è costruito passando un oggetto Runnable invoca il run di tale oggetto altrimenti non fa nulla start() manda il thread in esecuzione causando l’invocazione del metodo run sleep (long t) isAlive(), metodo boolean che testa se il thread è vivo
Conto corrente Scrivere un programma che gestisca un conto corrente bancario con operazioni di saldo, versamento e prelievo, si richiede che il conto l’ammontare del conto non sia mai negativo. Si simuli un’interazione di utenti cointestatari del conto che simultaneamente richiedono operazioni di prelievo, e saldo.
Classe Object Ogni oggetto ha un lock, cioè una variabile booleana, Ogni metodo può essere dichiarato synchronized. Quando un thread cerca di eseguire un metodo dichiarato synchronized si possono verificare due casi: il lock dell’oggetto è disponibile, in questo caso il thread acquisisce il lock esegue il metodo e rilascia il lock, il lock dell’oggetto non è disponibile, in questo caso il thread viene messo in attesa, che il lock si liberi.
Problema del buffer Scrivere un programma che gestisca un buffer che contiene un valore intero, con due processi il produttore che scrive valori nel buffer e il consumatore che legge valori dal buffer. Si richiede che non ci sia perdita di valori, ogni valore scritto deve essere letto. La soluzione usa una variabile booleana che indica se il valore memorizzato nel buffer è stato letto dal consumatore o no. Le operazioni di get e put testano la variabile prima di restituire il valore o di modificarlo.
Metodi wait e notify Per gestire alcune situazioni complesse la classe object ha i seguenti metodi, che possono essere invocati dentro un metodo synchronized: il metodo wait che mette il thread in attesa di una notify, rilasciando il lock, notify() e notifyAll() che segnalano ad eventuali thread in attesa (che abbiano cioè eseguito una wait) il verificarsi di una condizione,
Monitor La classe cella nell’esempio definita per la soluzione del problema del buffer è un monitor: Un monitor è tipo di dato astratto, cioè un oggetto in cui l’accesso ai dati avviene attraverso i suoi metodi e i metodi sono sincronizzati.
Annidamento di metodi sincronizzati Che succede se in un metodo synchronized invoco un altro metodo syncronized, dello stesso oggetto? Genero un dead lock? Tutto funziona correttamente? Vediamo un esempio: il programma del Conto corrente in cui il prelievo invoca il saldo.
Proprietà dei programmi concorrenti I programmi concorrenti devono godere delle seguenti proprietà: Correttezza dei dati, l’esecuzione concorrente di processi che operano sugli stessi dati non deve generare inconsistenze. Non generano deadlock, un deadlock è una situazione in cui il programma concorrente non termina perchè i processi che lo costituiscono aspettano una condizione che non si verificherà mai.