




































Studia grazie alle numerose risorse presenti su Docsity
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Prepara i tuoi esami
Studia grazie alle numerose risorse presenti su Docsity
Prepara i tuoi esami con i documenti condivisi da studenti come te su Docsity
Trova i documenti specifici per gli esami della tua università
Preparati con lezioni e prove svolte basate sui programmi universitari!
Rispondi a reali domande d’esame e scopri la tua preparazione
Riassumi i tuoi documenti, fagli domande, convertili in quiz e mappe concettuali
Studia con prove svolte, tesine e consigli utili
Togliti ogni dubbio leggendo le risposte alle domande fatte da altri studenti come te
Esplora i documenti più scaricati per gli argomenti di studio più popolari
Ottieni i punti per scaricare
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Riassunto di sincronizzazione tra piu processi in java
Tipologia: Appunti
1 / 44
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!





































Come si può realizzare il concetto di Thread in Java?
NEL MODO PIÙ NATURALE! Sono oggetti particolari ai quali si richiede un servizio (chiamato start()) corrispondente al lancio di una attività, di un thread! MA : non si aspetta che il servizio termini, esso procede in concorrenza a chi lo ha richiesto!
Normale Richiesta di Servizio
Richiesta di Servizio start() a un Thread
Flusso di Esecuzione
Esecuzione del Metodo X in B
B.X()
return
Attesa che Termini la Esecuzione di B.X()
Oggetto A
Oggetto B Da qui in poi ci sono due esecuzione,flussi di l'oggetto A non aspetta che termini l'esecuzione dell'oggetto B
Esecuzione del Metodo run() in B
B.start()
Oggetto A
Oggetto Thread B
Un thread ( lightweight process ) è un singolo flusso sequenziale di controllo all’interno di un processo
Un thread :
Esempio di classe SimpleThread che è
sottoclasse di Thread (modalità 1):
public class SimpleThread extends Thread { public SimpleThread(String str) { super(str); } public void run () { for (int i = 0; i < 10; i++) { System.out.println(i +" "+ getName()); try { sleep((int)(Math.random()*1000)); } catch (InterruptedException e){} } System.out.println("DONE! " +getName()); } }
public class TwoThreadsTest { public static void main (String[] args) { new SimpleThread("Jamaica"). start (); new SimpleThread("Fiji"). start (); } }
E se occorre definire thread che non siano necessariamente sottoclassi di Thread?
classe
con un’altra new , passando come parametro l’istanza della classe che si è creata
creato, producendo la chiamata al suo metodo run()
Interfaccia Runnable:
maggiore flessibilità derivante dal poter essere sottoclasse di qualsiasi altra classe
start() fa partire l’esecuzione di un
thread. La macchina virtuale Java invoca il metodo run() del thread appena creato
stop() forza la terminazione
dell’esecuzione di un thread. Tutte le risorse utilizzate dal thread vengono immediatamente liberate (lock inclusi), come effetto della propagazione dell’eccezione ThreadDeath
suspend() blocca l'esecuzione di un thread in attesa di una successiva operazione di resume. Non libera le risorse impegnate dal thread (possibilità di deadlock )
resume() riprende l'esecuzione di un
thread precedentemente sospeso. Se il thread riattivato ha una priorità maggiore di quello correntemente in esecuzione, avrà subito accesso alla CPU, altrimenti andrà in coda d'attesa
stop() e suspend() rappresentano azioni “brutali” sul ciclo di vita di un thread => rischio di determinare situazioni di blocco critico ( deadlock )
Infatti:
Î JDK 1.2, pur supportandoli ancora per ragioni di back-compatibility , sconsiglia l’utilizzo dei metodi stop(), suspend() e resume() ( metodi deprecated )
Si consiglia invece di realizzare tutte le azioni di controllo e sincronizzazione fra thread tramite i metodi wait() e notify() su variabili condizione (astrazione di monitor )
Scheduling : esecuzione di una molteplicità di thread su una singola CPU, in un qualche ordine
Macchina virtuale Java (JVM) Fixed Priority Scheduling : algoritmo di scheduling molto semplice e deterministico
La classe Thread fornisce i metodi:
con valori di num compresi fra
MIN_PRIORITY e MAX_PRIORITY (costanti
definite anch’esse nella classe Thread)
Quando due o più thread eseguono concorrentemente, è in generale impossibile prevedere l'ordine in cui le loro istruzioni verranno eseguite.
Problemi nel caso in cui i thread invocano metodi sullo stesso oggetto di cui condividono il riferimento. SONO POSSIBILI INCONSISTENZE!
Esempio: Oggetto conto_corrente con metodo versamento(importo) public void versamento(int importo) { int nuovo_totale; //variabile locale al metodo nuovo_totale = totale_conto + importo - tasse; //totale_conto è una variabile dell'oggetto //e indica i soldi totali sul conto //l'istruzione calcola il nuovo totale del //conto corrente mettendo il risultato nella //variabile locale totale_conto = nuovo_totale; //metto il totale calcolato nella variabile //dell'oggetto che memorizza il conto totale } Supponiamo che due thread abbiano entrambi un riferimento all'oggetto e invochino separatamente il metodo versamento per fare ognuno un versamento sul conto…
Supponiamo che l'oggetto conto_corrente abbia nella sua variabile totale_conto il valore 2000. Ci si aspetta che se qualcuno deposita 1000 e qualcun altro deposita 500 , e supponendo che le tasse per ogni versamento siano 100 , alla fine la variabile totale_conto valga 3300. Supponiamo che questi due depositi vengano fatti in concorrenza da due thread diversi e che durante l'esecuzione i thread si alternino sul processore, come segue Thread A Thread B
conto_corrente.versamento(1000) // il thread invoca il metodo e il flusso di esecuzione fa a eseguire le istruzioni di tale metodo
nuovo_totale= totale_conto+importo-tasse; //nuovo_totale = 2000+1000-
totale_conto = nuovo_totale; //totale_conto vale 2900
conto_corrente.versamento(500) // il thread invoca il metodo e il flusso di esecuzione fa a eseguire le istruzioni di tale metodo
nuovo_totale= totale_conto+importo-tasse; //nuovo_totale = 2000+500-
totale_conto = nuovo_totale; //totale_conto vale 2400
Alla fine, totale_conto vale 2400!!!! Il metodo versamento() non è atomico
In pratica: a ogni oggetto Java è automaticamente associato un lock per accedere a un metodo o una sezione synchronized, un thread deve prima acquisire il lock dell’oggetto il lock è automaticamente rilasciato quando il thread esce dalla sezione synchronized, o se viene interrotto da un’eccezione un thread che non riesce ad acquisire un lock rimane sospeso sulla richiesta della risorsa fino a che il lock non è disponibile
Quando un thread in esecuzione tenta di accedere ad una sezione synchronized di un oggetto il cui lock è già stato acquisito da un altro thread, che esegue concorrentemente, esso si mette in attesa di poter acquisire il lock. Il thread rimane in stato runnable. Appena il lock è rilasciato, lo scheduler può potenzialmente mettere in esecuzione il thread.
NOTA: ad ogni oggetto contenente metodi o blocchi synchronized viene assegnata una sola variabile condizione Î Due thread non possono accedere contempo- raneamente a due sezioni synchronized diverse di uno stesso oggetto
ESEMPIO – Lettura Dati da Socket .... public class AsyncReadSocket extends Thread { private Socket s; private StringBuffer result; public AsyncReadSocket(Socket s) { this.s = s; result = new StringBuffer(); } public void run() { DataInputStream is = null; try { is=new DataInputStream(s.getInputStream()); } catch (Exception e) {} while (true) { try { char c = is.readChar(); result.append(c); } catch (Exception e) {} } } public String getResult() { //metodo usato da un altro thread per leggere //la stringa letta dalla socket String retval = result.toString(); result = new StringBuffer(); return retval; } }
ESEMPIO MODIFICATO .... public class AsyncReadSocket extends Thread { private Socket s; private StringBuffer result; public AsyncReadSocket(Socket s) { this.s = s; result = new StringBuffer(); } public void run() { DataInputStream is = null; try { is=new DataInputStream(s.getInputStream()); }catch(Exception e){} while (true) { try{ char c = is.readChar(); appendResult(c); }catch(Exception e){} } } public synchronized String getResult() { String retval = result.toString(); Result = new StringBuffer(); return retval; } public synchronized void appendResult(char c) { result.append(c); }}
=> non avremmo risolto i problemi di corsa critica
La mutua esclusione durerebbe all’infinito e due Thread di tipo AsynchReadSocket non potrebbero eseguire concorrentemente