Il 0% ha trovato utile questo documento (0 voti)
4 visualizzazioni

JavaThread

Caricato da

sabry.minali
Copyright
© © All Rights Reserved
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd
Il 0% ha trovato utile questo documento (0 voti)
4 visualizzazioni

JavaThread

Caricato da

sabry.minali
Copyright
© © All Rights Reserved
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd
Sei sulla pagina 1/ 8

Università degli Studi di Modena e Reggio Emilia

PROCESSI
Facoltà di Ingegneria
Nei sistemi concorrenti (multiprogrammati), il termine processo
denota la singola attività eseguita in modo indipendente e
separato rispetto alle altre.
• Tipicamente, un programma è eseguito da un processo.
CORSO DI
• Il processo è l'istanza in esecuzione di un processo
• Più processi possono eseguire lo stesso programma.
RETI DI CALCOLATORI Paragone con Classi e Oggetti: un programma agisce come una
Linguaggio Java: i Thread classe, il processo rappresenta una instanza in esecuzione del
programma.
Un processo:
Prof. Franco Zambonelli
• è del tutto autonomo e indipendente dagli altri processi
Lucidi realizzati in collaborazione con • ha un prorpio spazio di indirizzamento riservato (porzione di
Ing. Enrico Denti - Univ. Bologna memoria RAM) e non condivide memoria con altri processi:
significa che anche le variabili globali sono private al processo
• ha un proprio stack riservato (quindi anche le variabili locale
sono private al processo).
La comunicazione tra processi distinti non può quindi avvenire in
modo “diretto” (per condivisione di variabili), ma deve sfruttare
appositi meccanismi di sistema (p.e., file o socket).

I processi servono ad avere attività in esecuzione concorrente MA


indipendente, minimizzando le possibilità di interazione, e quindi
di disturbo reciproco

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 1 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 2

ESEMPIO THREAD
Quando da una finestra lancio un server, e poi da un'altra Spesso si vogliono realizzare programmi in cui non vi è solo una
finestra lancio un client, questi due programmi in attività in esecuzione, ma in cui diverse attività in concorrenza
esecuzione sono processi diversi, e non possono interagire eseguono (motivi di efficienza dell'esecuzione). In questo caso, vi
se non tramite la scrittura di parti comuni di file o attraverso è può l'esigenza forte di fare interagire le diverse attività in
comunicazione via socket!!! esecuzione.

Un thread (o processo leggero):


• è un’attività autonoma che “vive” all’interno di un processo
(e quindi, tipicamente, la stessa istanza in esecuzione di un
programma, corrispondente a un processo, ospita al suo interno
dei sotto-flussi di esecuzione concorrente, corrispondenti ai
thread)
• ..ma non ha uno spazio di indirizzamento riservato: tutti i
thread appartenenti allo stesso processo condividono il
medesimo spazio di indirizzamento. (le variabili globali in
RAM)
• ha un proprio stack riservato (e quindi le sue variabili locali
di una procedura sono private e non condivise da altri thread)
La a comunicazione fra thred può quindi avvenire in modo molto
più semplice, tramite lo spazio di memoria condiviso. Quindi, se
ci sono variabili globali o riferimenti a aree di memoria od oggetti
comuni diversi thread possono interazione.
Occorre però disciplinare l’accesso a tale area comune
→ necessità di opportuni meccanismi di sincronizzazione.
In un liguaggio ad oggetti: ovviamente, il concetto di variabile
globale non hanno senso. Però più thread possono condividere
riferimenti allo stesso oggetto, interagiscono tramite tale oggetto.

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 3 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 4
LA CLASSE Thread
THREAD IN JAVA
La classe Thread è la base per la gestione dei thread in Java.
Come si può realizzare il concetto di Thread in Java?
Essa comprende metodi per attivare, fermare, sospendere,
NEL MODO PIU' NATURALE! Sono oggetti particolari ai quali riprendere, attendere thread, per controllarne la priorità, lo
si richiede un servizio (chiamato start()) corrispondente al scheduling, etc.
lancio di una attività, di un thread! MA: non si aspetta che il
servizio termini, esso procede in concorrenza a chi lo ha richiesto!
Il corpo del thread è costituito dal metodo run()

Quindi, per definire una nuova classe di thread si deve:


Normale Richiesta di Richiesta di Servizio start() a
Servizio un Thread • definire una propria sottoclasse di Thread che ridefinisca
opportunamente il metodo run()
Oggetto A Oggetto A
Flusso di Per creare un nuovo oggetto thread si dovrà quindi:
Esecuzione
• creare una istanza della propria sottoclasse di Thread sopra
Oggetto definita
Oggetto B Da qui in poi Thread B
B.X() ci sono due B.start()
Attesa che flussi di
Per far partire il nuovo thread (cioè l'esecuzione del suo metodo
Termini la Esecuzione esecuzione, Esecuzione run())basta poi invocare su di esso il metodo start().
Esecuzione del Metodo l'oggetto A del Metodo
di B.X() X in B non aspetta run() in B
return che termini
l'esecuzione
dell'oggetto B

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 5 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 6

ESEMPIO L'INTERFACCIA Runnable


Creazione di un thread a partire dalla classe Thread
La nuova classe di thread… Il metodo run() dei Thread è anche dichiarato nella interfaccia
class MyThread1 extends Thread { Runnable. Quindi, come metodo alternativo per definire dei
public void run(){
thread si può:
for(int i=1; i<=10; i++) • definire una propria classe che implementi l’interfaccia
System.out.println(i + " " + i*i); Runnable, definendo il metodo run().
}}
… e la corrispondente classe di test che lo crea e lo attiva:
public class Esempio1 {
Questa via è più flessibile, (rispetto all'ereditare dalla classe
Thread) in quanto consente di definire classi di thread che non
public static void main(String args[]){
MyThread1 t1 = new MyThread1(); siano per forza sottoclassi di Thread ma che siano sottoclassi di
t1.start(); altri classi generiche.
// o anche: new MyThread1().start();
}} E’ il discorso che era stato fatto nella ereditarietà
NOTE: multipla….vogliamo definire delle classi che ereditino da altre
classi, quelle che servono nello specifico problema, e poi fare in
• la versione con la variabile t1 esplicitamente definita è utile modo che questa classe abbia anche le proprietà dei threads.
qualora su t1 debbano essere invocati altri metodi oltre Poiché non possiamo ereditare sia da Threads che dalla classe di
all’iniziale start() interesse, usiamo il concetto di interfaccia:
• il nuovo thread continua (in questo caso) la propria esecuzione • ereditiamo dalla classe di interesse
fino alla sua terminazione naturale; altrimenti, potrebbe essere • poi implementiamo la interfaccia runnable
espressamente fermato da un altro thread che invochi su di esso
il metodo stop().
Per creare e usare un thread quindi bisogna:
• ogni Thread ha sempre associato un nome univoco,
corrispondente a una stringa, che o viene assegnato di default • prima creare una istanza della propria classe (che implementa
dal sistema o viene assegnato dall'utente in fase di l’interfaccia Runnable)
inizializzazione! Provare:

Thread.currentThread().getName(); • poi creare una istanza di Thread a partire da tale oggetto


(incapsulandovi tale oggetto).

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 7 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 8
ESEMPIO CONTROLLO DEI THREAD
• un thread continua la propria esecuzione o fino alla sua
terminazione naturale, o fino a che o fino a che non viene
Creazione di un thread tramite l’interfaccia Runnable
espressamente fermato da un altro thread che invochi su di esso
La nuova classe di thread… il metodo stop()
class MyBody3 implements Runnable {
// NON DERIVA DA Thread! • un thread può anche essere sospeso temporaneamente dalla sua
esecuzione
public void run(){
for(int i=1; i<=10; i++) • perché un operazione blocca l'esecuzione, come una
System.out.println(i + " " + i*i); operazione di input che implica di attendere dei dati. Il
} Thread si blocca finchè i dati non sono disponibili.
} • perché invoca la funzione Thread.sleep();
… e la corrispondente classe di test che lo crea e lo attiva: • da un altro thread che invochi su di esso il metodo
suspend(), per riprendere poi la propria esecuzione
public class Esempio3 { quando qualcuno invoca su di esso il metodo resume().
public static void main(String args[]){
MyBody3 b3 = new MyBody3(); La classe di thread opportunamente modificata…
Thread t = new Thread(b3);
// o anche: class MyThread2 extends Thread {
// Thread t = new Thread(new MyBody3()); public void run(){
for(int i=1; true; i++) // ciclo infinito
t.start(); System.out.println(i + " " + i*i);
} }}
}
… e la corrispondente classe di test che crea e gestisce il thread:
public class Esempio2 {
public static void main(String args[]){
MyThread2 t2 = new MyThread2();
t2.start();
Thread.sleep(1000); // sleeps 1 sec
t2.suspend();
Thread.sleep(1500); // sleeps 1,5 sec
t2.resume();
Thread.sleep(300); // sleeps 0,3 sec
t2.stop();
}}

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 9 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 10

stop, suspend, resume: PROBLEMI CONTROLLO DEI THREAD: JOIN


ATTENZIONE! stop(), suspend() e resume() sono deprecati
in Java2, in quanto non sicuri.
Si può decidere di aspettare che termini l'esecuzione di un thread.
Questi tre metodi agiscono in modo brutale su un thread (che non Per fare questo, bisogna invocare l'operazione join() sul thread che
può “difendersi” in nessun modo), e così facendo rischiano di si intende aspettare
creare situazioni di blocco (deadlock):
Oggetto A
• se il thread sospeso / fermato stava facendo un’operazione
critica, essa rimane a metà e l’applicazione viene a trovarsi in
uno stato inconsistente Oggetto
Da qui in poi ci Thread B
• se il thread sospeso / fermato aveva acquisito una risorsa, essa sono due flussi di
esecuzione,
B.start()
rimane bloccata da quel thread e nessun altro può conquistarla l'oggetto A non Esecuzione
aspetta che termini del Metodo
• se a questo punto un altro thread si pone in attesa di tale risorsa, l'esecuzione run() in B
dell'oggetto B
si crea una situazione di deadlock.
E infatti, se nell’esempio precedente si aggiungono delle
println() nel main, tutto si pianta alla prima suspend()!!
Quando però A fa
B.join(), la sua
esecuzione si B.join()
LA SOLUZIONE sospende nell'attesa
che il Thread B
La soluzione suggerita da Java 2 consiste nell’adottare un diverso termini la sua
esecuzione
approccio:
• non agire d’imperio su un thread,
E' come se ci fosse
• ma segnalargli l’opportunità di sospendersi / terminare, un ri-
congiungimento
• lasciando però al thread il compito di sospendersi / termi- dei flussi di
esecuzione
nare, in modo che possa farlo in un momento “non critico”.
• la funzione yeald() permette a un thread di cedere l'esecuzione
ad un altro!

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 11 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 12
ESEMPIO DI JOIN UNA VARIANTE:
Creazione di una serie di thread con nome in sequenza
Creazione di una serie di thread in sequenza
class Esempio4 { class Esempio4bis {
public static void main(String args[]){ public static void main(String args[]){
System.out.println("Main - inizio"); System.out.println("Main - inizio");
while(true) { int i=1;
MyThread4 t = new MyThread4(b4); while(true) {
System.out.print("new " + Thread t = new MyThread4("Enrico" + i++);
(t==null ? "fallita" : "riuscita")); System.out.print("new " +
System.out.println(" (CTRL-C per finire)"); (t==null ? "fallita" : "riuscita"));
t.start(); System.out.println(" (CTRL-C per finire)");
try { t.start();
t.join(); // attende che t termini try {
} t.join(); // attende che t termini
catch(InterruptedException e) {} }
} } } catch(InterruptedException e) {}
} }}
class MyThread4 extends Thread {
public void run(){ class MyThread4 extends Threads {
System.out.println("Qui thread " + public void run(){
Thread.currentThread().getName() ); System.out.println("Qui thread " +
} Thread.currentThread().getName() );
} }}

NOTE: NOTA:
• il main è un ciclo infinito che crea continuamente nuovi thread • la classe Thread ha sia un costruttore con un solo argomento
(fino a che non viene chiuso con CTRL-C) (che si aspetta un oggetto che implementi Runnable) sia uno
• prima di creare un nuovo thread, il main attende, tramite con due argomenti, che all’oggetto Runnable affianca un
join(), che termini quello precedentemente in esecuzione oggetto String che si assume essere il nome del thread.
• l’attesa di join() potrebbe essere interrotta da un’eccezione
→ necessità di try/catch

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 13 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 14

SCHEDULING LA POLITICA DELLO SCHEDULER


ESEMPIO
In un sistema monoprocessore i thread devono condividere
class Esempio5 {
l'esecuzione su un unico processore. A un certo istante, ci sarà un
public static void main(String args[]){
solo thread realmente in esecuzione, e altri in attesa di acquisire il System.out.println("Main - inizio");
controllo del processore.
Quando viene rilasciato il processore? new MyThread5("cip ").start();
new MyThread5("ciop").start();
• quando si involcano dei metodi di controllo, come
sospend(), resume, stop(), che permettono di // NB: se è non-preemptive, va solo cip
// se è preemptive, vanno entrambi
gestire l'uso del processore, e fare in modo che un thread, }
bloccandosi o sospendendosi, ceda il processore. }
• quando un processo invoca una operazione che implica attesa di
qualche evento, come un'operazione di input, durante la quale class MyThread5 extends Thread {
public void run(){
attesa non ha bisogno del processore; while (true)
System.out.println(
Nei casi sopra, il controllo del processore viene ovviamente Thread.currentThread().getName() );
ceduto a un altro thread. Altrimenti, se i thread non vengono }
esplicitamente bloccati o se non fanno operazioni che implicano }
attesa:
• scheduling nonpreemptive se il controllo del microprocessore
non viene mai forzatamente tolto al thread corrente NOTA:
• scheduling preemptive in condivisione di tempo (time sharing) • cip e ciop sono due thread che eseguono lo stesso codice b5,
se i thread possono eseguire ininterrottamente solo per un certo che è un ciclo infinito: quindi, in presenza di scheduling non
intervallo di tempo, dopo di che sono forzati a cedere il preemptive andrà sempre e solo cip. Se vanno entrambi, lo
microprocessore algi altri thread in attesa.. scheduling è certamente preemptive (caso JDK Windows).
Java non precisa quale tipo di multitasking debba essere
adottato dalla macchina virtuale! Dipende dal Sistema
Operativo!
Però, non è difficile verificarlo con un piccolo test.

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 15 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 16
COROUTINING INTERAZIONE TRA THREAD
Indipendentemente dalla politica di scheduling dei adotata dalla
macchina virtuale, è facile in Java costruire due thread che si Supponiamo di avere questa classe di Thread
cedono reciprocamente il controllo (schema cosiddetto di co-
class ThreadCC extends Thread {
routining) Counter c;
int i;
public ThreadCC(Counter cc)
ESEMPIO 6 - Esempio di coroutining fra due thread { c = cc; }

public void run(){


class Esempio6 { for( i=1; i<=10; i++)
public static void main(String args[]){ {System.out.println(“i vale: " + i);
System.out.println("Main - inizio"); c.inc();
System.out.println(„Count vale: “ + c.rd());
new MyThread6("cip ").start(); }}}
new MyThread6("ciop").start();
}} … e una classe di test che crea due oggetti thread della stessa
classe e poi li attiva.
class MyThread6 extend Thread {
public void run(){ La classe passa come parametro in fase di creazione il riferimento
while (true) { allo stesso oggetto Count
System.out.println(
Thread.currentThread().getName()); public class EsempioCC {
Thread.yield(); // cede l'esecuzione ad un public static void main(String args[]){
// altro thread Counter c = new Counter();
} } } ThreadCC t1 = new ThreadCC(c);
ThreadCC t2 = new ThreadCC(c);
Dopo avere scritto il nome, un trehad cede il controllo all'altro t1.start();
thread, rimettendosi in coda in attesa di poter ri-acquisire t2.start();
l'esecuzione. // o anche: new MyThread1().start();
}}
NOTA:L’output può non essere un rigoroso alternarsi
cip / ciop, perché in mezzo può inserirsi lo scheduler ORA: i due thread non condividono la variabile i, che esiste in
(preemptive). due diverse versioni per i due thread (come è sempre per qualsiasi
oggetto). PERO’: i due oggetti hanno riferimento allo stesso
oggetto contatore, che risulta perciò condiviso, e i due thread
interagiscono indirettamente tramite tale contatore

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 17 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 18

SINCRONIZZAZIONE di THREADS ESEMPIO DI INCONSISTENZA


Quando due o più thread eseguono concorrentemente, è in Supponiamo che l'oggetto conto_corrente abbia nella sua
generale impossibile prevedere l'ordine in cui le loro istruzioni variabile totale_conto il valore 2000. Ci si aspetta che se
verranno eseguite. qualcuno deposita 500 e qualcun altro deposita 1000, e
supponendo che le tasse per ogni versamento siano 100, alla fine
Problemi nel caso in cui i thread invocano metodi sullo stesso la variabile totale_conto valga 3300.
oggetto di cui condividono il riferimento. SONO POSSIBILI
INCONSISTENZE! 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
Esempio:
Oggetto conto_corrente Thread A Thread B
con metodo versamento(importo)
conto_corrente.versamento(1000)
public void versamento(int importo) // il thread invoca il metodo e il flusso di
{ int nuovo_totale; //variabile locale esecuzione fa a eseguire le istruzioni di
tale metodo
nuovo_totale = totale_conto + importo - tasse; conto_corrente.versamento(500)
//totale_conto è una variabile dell'oggetto // il thread invoca il metodo e il flusso di
//e indica i soldi totali sul conto esecuzione fa a eseguire le istruzioni di
//l'istruzione sopra calcola in nuovo totale del tale metodo
// conto corrente mettendo il risultato nella nuovo_totale=
//variabile locale totale_conto+importo-tasse;
//nuovo_totale = 2000+1000-100
totale_conto = nuovo_totale;
// metto il totale calcolato nella variabile nuovo_totale=
//dell'oggetto che memorizza il conto totale totale_conto+importo-tasse;
} //nuovo_totale = 2000+500-100

Supponiamo che due thread abbiano entrambi un riferimento totale_conto =nuovo_totale;


all'oggetto invochino separatamente il metodo versamento per fare //totale_conto vale 2900
totale_conto = nuovo_totale;
ognuno un versamento sul conto…. //totale_conto vale 2400

Alla fine, totale_conto vale 2400!!!!

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 19 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 20
SEZIONI CRITICHE ESEMPIO – Conto Corrente
Sincronizzato
Le sezioni di codice in cui si accede a risorse e oggetti comuni
(condivise) sono critiche: per evitare inconsistenze, è necessario
assicurare che, prima di entrarvi, i thread si sincronizzino, in Public class CC {
modo da garantire che solo un thread per volta possa eseguire la Int totale_conto;

sezione critica. Nell'esempio precedente, bisogna evitare che due public synchronized void versamento(int importo)
thread eseguano in concorrenza in metodo versamento. { int nuovo_totale; //variabile locale
nuovo_totale = totale_conto + importo - tasse;
In Java si può garantire l’accesso in mutua esclusione a una totale_conto = nuovo_totale;
istanza, proteggendo il metodo o la sezione di codice critica }
tramite la keyword synchronized: }

• metodo sincronizzato:
class ThreadCC extends Thread {
public synchronized void setValue() {...} CC c;
Solo un thread alla volta può eseguire questo metodo sullo public ThreadCC(CC cc)
{ c = cc; }
stesso oggetto.
• sezione di codice sincronizzata: public void run(){
for( i=1; i<=10; i++)
synchronized(object) {...} cc.versamento(i*1000);
Solo un thread alla volta può eseguire la parte di codice }}}
protetta sull’oggetto object (che può essere this).
public class EsempioCC {
Nell'esempio precedente: public static void main(String args[]){
• il metodo versamento deve essere synchronized CC c = new CC();
ThreadCC t1 = new ThreadCC(c);
• mentre il flusso di esecuzione di un thread esegue tale metodo, ThreadCC t2 = new ThreadCC(c);
è garantito che nessun'altro thread potrà eseguirlo t1.start();
t2.start(); }}
• se Thread A sta già esegunedo il metodo, quando Thread B
tenta di eseguirlo viene sospeso, in attesa che Thread A termini
• quando Thread A termina, Thread B riprende l'esecuzione a può
eseguire il metodo versamento.
NESSUNA INCONSISTENZA!!!!!

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 21 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 22

ESEMPIO - Uso dello stack


ESEMPIO – Stack Sincronizzato Questo codice riunisce in sé tre attività diverse: il pusher (che
inserisce nello stack dato 20 oggetti Integer), il popper (che li
class EmptyStackException extends Exception { estrae), e il printer (che visualizza lo stato dello stack).
EmptyStackException() {}
EmptyStackException(String s) { super(s); } Ogni istanza di MyBody9 si comporterà quindi o come pusher, o
} come popper, o come printer, a seconda del nome che le viene
passato all’atto della costruzione.
class Stack {
Object val[]; class MyBody9 implements Runnable {
int sp = 0; String chiSonoIo;
static Stack s = new Stack(100); // condiviso
Stack(int max) { val = new Object[max]; } MyBody9(String name){ chiSonoIo = name; }
public synchronized void push(Object e) { public void run(){
val[sp++]=e; if (chiSonoIo.equals("pusher")) {
} for(int i=0; i<20; i++) {
public synchronized Object pop() System.out.println(
throws EmptyStackException { Thread.currentThread().getName()
+ " pushing " + i);
if (sp>0) return val[--sp]; s.push( new Integer(i) );
else throw new EmptyStackException(); } } else
} if (chiSonoIo.equals("popper")) {
public boolean isEmpty() { return (sp==0); } try { Thread.sleep(500); }
catch (InterruptedException ee) {}
public void print() { try {
System.out.print("Stack content: ["); while(!(s.isEmpty()))
for(int i=0; i<sp-1; i++) System.out.println(
System.out.print(val[i] + ", "); Thread.currentThread().getName()
if (sp>0) System.out.print(val[sp-1]); + " popping " + s.pop());
System.out.print("]"); } catch (EmptyStackException e) {
} System.out.println(
} Thread.currentThread().getName()
+ " tried to pop an empty stack"); }
} else /* sono il printer */
s.print();
}}

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 23 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 24
ESEMPIO - Uso dello stack I THREADS NELLA PROGRAMMAZIONE
public class Esempio9 { DI RETE
public static void main(String args[]){
// creo tre istanze configurate diversamente I threads risultano fondamentali per avere programmi di rete
MyBody9 b1 = new MyBody9("pusher"); efficienti e flessibili
MyBody9 b2 = new MyBody9("popper");
MyBody9 b3 = new MyBody9("printer");
// creo tre thread, uno per task da eseguire PROBLEMA BASE:
Thread t1 = new Thread(b1, "Produttore"); Quando un server sta svolgendo il suo servizio per uno specifico
Thread t2 = new Thread(b2, "Consumatore"); cliente, non può accettare richieste di connessione da altri clienti
Thread t3 = new Thread(b3, "Visualizzatore"); SOLUZIONE:
// ora attivo Produttore e Consumatore… il server, quando deve fornire un servizio, non lo fa lui. Invece,
t2.start(); crea un thread il quale è delegato a svolgere il servizio. Il server,
t1.start(); di per sé, può rimanere in ascolto di ulteriori richieste di
// …e aspetto che finiscano entrambi connessioni e servirle
try { t1.join(); }
catch(InterruptedException e1) {} ALTRI PROBLEMI:
try { t2.join(); } Le operazioni di lettura, scrittura, e di attesa connessioni sono
catch(InterruptedException e2) {} operazioni bloccanti. Se non c’è chi scrive, legge, o si connette, il
// alla fine attivo il Visualizzatore programma non fa nient’altro che aspettare. Magari potrebbe
t3.start();
eseguire altri pezzi del programma utili.
} SOLUZIONE:
} Creare più thread, lasciare un thread in attesa nelle operazioni
NOTA: bloccanti, mentre gli altri thread vanno avanti con il programma.
• a rigore, esiste ancora un rischio di inconsistenza sugli oggetti
memorizzati nello stack, in quanto si memorizzano riferimenti: CORRELATO A CIO’:
altri thread potrebbero fare riferimento agli stessi oggetti, e In molti casi, i programmi di rete agiscono sia da clienti che da
modificarli mentre sono memorizzati nello stack servitori, ed è bene che le due cose possano svolgersi in modo
• sarebbe più sicuro archiviare nello stack delle copie (cloni) indipendente….così la parte servitore è sempre disponibile a
degli oggetti anziché mantenere dei riferimenti servire e la parte cliente può continuare a chiedere altri servizi…

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 25 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 26

SERVER CONCORRENTI ESEMPIO:TIMER CONCORRENTE


Si crea un nuovo thread per servire ogni richiesta di servizio.
Poiché ad ogni nuova connessione che si accetta viene creata una IL THREAD CHE SVOLGE IL SERVIZIO
nuova socket, non c’e’ conflitto: ogni Thread lavora su una socket
diversa. Non c’è problema di sincronizzazione.
class TimeServerT extend Thread {

SCHEMA GENERICO: Socket s;


class ServerThread extend Thread {
Socket s; Public ServerThread (Socket s)
Public ServerThread (Socket s) { this.s = s; }
{ this.s = s; }
public void run(){ public void run(){
// codice del servizio
try {
}
} System.out.println(“Thread Partito”)
OutputStream os =
public class MainServer { s.getOutputStream();
public static void main(String args[]){
ServerSocket ss = null; PrintStream outp = new PrintStream(s);
ServerThread t; outp.println(new java.util.Date());
try { s.close();
ss = new ServerSocket(7777);
while (true) { }
Socket clientSock = ss.accept(); } catch (UnknownHostException e){
T = new ServerThread(clientSock); System.err.println("Host unknown");
T.start()
} catch (Exception e){
}
} catch (Exception e){ System.err.println(e);
System.err.println(e); }}
} }
}
}

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 27 Franco Zambonelli, Enrico Denti - THREAD IN JAVA 28
ESEMPIO:TIMER CONCORRENTE

IL MAIN SERVER CHE ACCETTA LE CONNESSIONI

public class MainServer {


public static void main(String args[]){
ServerSocket ss = null;
ServerThread t;
try {
ss = new ServerSocket(7777);
while (true) {
Socket clientSock = ss.accept();
T = new ServerThread(clientSock);
t.start();
}
} catch (Exception e){
System.err.println(e);
}
}
}

Franco Zambonelli, Enrico Denti - THREAD IN JAVA 29

Potrebbero piacerti anche