OOP0506_L21_Threads - Università degli Studi di Roma "Tor

Università degli Studi di Roma “Tor Vergata”
Facoltà di Ingegneria
Corso di Laurea in Ingegneria Informatica
Programmazione Orientata agli Oggetti
Processi, task e thread Java
(ed esempi)
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
1
processi
Un processo sequenziale denota una sequenza di attività
che può essere sviluppata in totale indipendenza.
I processi eventualmente si sincronizzano e comunicano.
La comunicazione può avvenire per puro scambio di
messaggi (Ambiente locale) o tramite accesso a variabili
condivide (“Shared memory” o Ambiente globale).
• Un processo è l’istanza di esecuzione di un programma
(“Applicazione”).
• Più processi possono essere istanziati nell’ambito della
esecuzione di uno stesso programma
• In presenza di un solo processore due processi non
possono essere eseguiti in reale parallelismo: essi si
alterneranno sulla risorsa di calcolo secondo la modalità di
gestione attuata dal del sistema operativo.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
2
Parallelismo e concorrenza
In presenza di un numero limitato di processori non
tutti i processi pronti per l’esecuzione possono essere
messi in esecuzione. Essi competono sulle limitate
risorse di calcolo disponibili.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
3
processi
• Due processi distinti hanno distinti
– Spazi di indirizzamento
– Memoria
• Heap
• Variabili locali (stack riservato)
• …….
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
4
Processi pesanti e leggeri
• I processi pesanti (“heavy”) ottengono
risorse e sono lanciati direttamente dal
sistema operativo.
• I processi leggeri (“light”) corrono nello
spazio di indirizzamento di un processo
pesante.
• Nel seguito i processi pesanti sono detti
semplicemente “processi”.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
5
Comunicazione fra processi
I processi, pesanti o leggeri che siano, devono
comunicare esclusivamente attraverso i
meccanismi previsti, messaggi o dati
condivisi, come meglio spiegato in altra parte
del corso “Comunicazione tra processi”
– Esempi: socket, shared memory,
monitor, canali etc.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
6
Processi in Java
Un’applicazione Java corre sempre nella
macchina virtuale, creata e avviata dal SO, e
insieme con qualche processo leggero,
denominato Thread .
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
7
Processi (leggeri) addizionali
in Java
In un’applicazione Java, processi leggeri
addizionali sono:
• creati per istanza della classe Thread (e.g. Thread
t= new Thread();) - o classe da questa derivata
con sovrascrittura del metodo run();
• avviati tramite t.start();
• terminati naturalmente ovvero forzatamente tramite
t.stop(), t.terminate() o per sollevamento di
eccezione (InterruptedException ).
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
8
Thread == Processo leggero
Un Thread denota un processo leggero,
un’attività indipendente che vive
all’interno di un processo (pesante)
• Due distinti oggetti thread hanno:
– Stack riservato
– Stesso spazio di indirizzamento
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
9
Thread - comunicazione
La comunicazione tra due thread Java può
avvenire tramite area di memoria condivisa
(“shared”), visibile e accessibile da
entrambi i thread

Necessità di disciplinarne l’accesso con
opportuni meccanismi e costrutti di
sincronizzazione e mutua esclusione.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
10
Java thread
• Java definisce in modo completo stati previsti
per un suo thread e relative transizioni. Per i
comportamenti, il programmatore può intervenire
solo con la ridefinizione del metodo run() e,
come si vedrà, di parti “sincronizzate”. Per il
resto, nulla cambia: si tratta pur sempre di
programmare e utilizzare classi.
• La attivazione di un thread consiste
nell’invocazione del metodo start() verso il
particolare oggetto thread, il quale, in risposta,
eseguirà concorrentemente al chiamante il corpo
del suo metodo run().
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
11
Java thread
Oggetto A
Oggetto B
onClick() new B()
start()
unMetodo()
2 luglio 2006
Oggetto C
Esecuzione del metodo
run() definito nella classe
B concorrentemente alla
continuazione
dell’esecuzione del metodo
onClick() in A
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
12
Java Thread
•
Quali le caratteristiche della classe B?
–
–
•
Discende dalla classe Thread
Implementa il metodo run() programmato per
svolgere la necessaria attività
Cosa deve fare la classe A?
1. Creare una istanza di B
2. Inviargli lo stimolo di start(); questo provvederà
a invocare il metodo run()
3. run() NON deve essere invocato direttamente da A.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
13
Esempio di thread (1/2)
Si realizzi un thread per stampare i numeri da 1 a 10
passo 1: definizione della classe:
public class MioThread extends Thread {
public void run() {
for (int i=1; 1<=10; i++)
System.out.println(i);
}
}
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
14
Esempio di thread (2/2)
passo 2: definizione della classe client di MioThread
public class EsempioUsoThread {
public static void main (String[]
a)
{
MioThread t = new MioThread();
t.start();
}
}
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
15
Problema: ereditarietà multipla
Se una classe deve ereditare da altra classe
allora non la si può rendere anche erede di
Thread perché Java NON prevede
ereditarietà multipla fra classi.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
16
Interfaccia Runnable
Si utilizza allora ereditarietà sia da (una) classe, sia da
interfacce. A tale scopo, Java prevede l’interfaccia
Runnable. Questa include la dichiarazione
dell’operazione run(). Thread implementa Runnable.
public class MioSchema extends
UnaClasseImportante implements
Runnable {…;}
Tramite l’uso della interface Runnable è possibile
separare il “corpo” del thread dal vero thread da lanciare.
Tale corpo viene infatti a costituire una sorta di template
dinamico di possibili istanze thread.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
17
Impiego di Runnable
Cosa deve fare allora una classe cliente? Essa:
1. Specializza in una nuova classe (e.g. class Schema) la
classe da cui deve ereditare e implementa l’interfaccia
Runnable;
2. Schema contiene, quindi, la definizione del metodo
run() dichiarato nell’interfaccia;
3. Crea una istanza di Schema, e.g. Schema sk=new
Schema();
4. Crea i necessarti Thread, passando a ciascuno di essi sk
come parametro, e.g.: Thread t1=new Thread
(sk), t2= new Thread (sk);
5. Avvia ciascuno dei thread creati , invocandoli
(indirettamente) tramite start(): e.g. t1.start();
t2.start();
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
18
Esempio: thread via Runnable
(1/2)
Runnable
L’interfaccia Runnable
contiene la dichiarazione del
metodo run()
implements
MioSchemaDiThread
2 luglio 2006
La classe MioSchemaDiThread
contiene l’implementazione del metodo
run() ma NON estende la classe
Thread
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
19
Esempio: thread via Runnable
(2/2)
public class EsempioUsoThread {
public static void main (String[] a)
{
MioSchemaThread bt =
new MioSchemaThread();
Thread t = new Thread (bt);
t.start();
}
}
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
20
Controllo accessi
(Mutua esclusione)
• Synchronized qualcheCosa
qualche cosa:: <metodo> |(this) {<blocco>) |
(<varIstanza>) {<blocco>} |
(getClass(){<blocco>}) | (Class.for.Name
(“<NomeVarStaticaPubblica>”)){<blocco>}):
– Rende mutuamente esclusivo l’accesso a “qualcheCosa”
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
21
Controllo esecuzione di Thread
• yeld()
– Il thread che lo esegue (fuori sincronizzazione!) dà la precedenza a
eventuali altri thread pronti per l’esecuzione. De facto applicabile in
caso di gestioni multiprogrammate (senza “preemtion”).
• sleep(t)
– Rende un thread (che sia fuori sincronizzazione!) non eseguibile per un
intervallo di tempo non minore di t. Consente a un eventuale processo
pronto di avanzare. Per il resto, vedere yeld().
• wait()
– Pone il thread che lo esegue in stato di attesa (WAITING).
“Dissincronizza” (sblocca l’accesso al monitor). Per cambiare lo stato di
un tale thread e portarlo in stato BLOCKED sarà necessaria l’occorrenza
di una notify() e sufficiente quella di una notifyAll().
• wait(t)
– Pone il thread che lo esegue in stato di attesa (WAITING).
“Dissincronizza” (sblocca l’accesso al monitor) . Per portare tale thread
in stato BLOCKED sarà necessaria l’occorrenza di una notify() e
sufficiente quella di una notifyAll() o che sia trascorso l’intervallo
di tempo t.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
22
Controllo esecuzione di Thread
Permettono a un thread di agire sullo stato di eventuali thread in stato di
“attesa” (WAITING) .
• notify()
– Fra gli eventuali (altri!) thread in stato di attesa (WAITING) in un
monitor Java, uno ne viene selezionato e reso pronto per ripendere la
propria computazione (BLOCKED) . Il thread notificante conserva il
conmtroillo del monitor.
• notifyAll()
– Equivale a notify() ma esteso a tutti i thread eventualmente in
attesa. Conseguentemente, WAITING.numeroThreads==0;
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
23
Controllo esecuzione di Thread
Permettono a un thread di agire anche su altro thread
• stop()
– Permette di abortire l’esecuzione di un thread. I monitor
ocuupati dal thread sono dissincronizzati nello stato in cui si
trovano (!)
•suspend()
– Sospende l’esecuzione del thread oggetto della suspend() (de
facto applicabili in caso di gestioni prioritarie con “preemtion”).
I monitor impegnati dal thread restano indisponibili. Per
riprendere un thread sospeso è necessaria un’apposita
resume().
•resume()
– Riprende l’esecuzione dal punto di sospensione
Anche da sistema è possibile abortire una intera esecuzione(Kill, Cntrl
C, etc.) generando una InterruptedException.
Tutti questi metodi agiscono “di forza”; il loro impiego da parte del
programmatore è deprecabile ed effettivamente (in Java2) “deprecato”:
possono lasciare uno stato inconsistente o bloccare un’applicazione!!
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
24
Problemi posti da
suspend
Se il thread che viene “sospeso” ha acquisito
una risorsa in uso esclusivo, altri thread,
compreso quello che ha comandato la
sospensione, avendo bisogno di utilizzare la
medesima risorsa, finiranno in attesa. Se solo
essi sono responsabili del resume() allora
l’applicazione finirà in blocco mortale.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
25
Problemi posti da
stop
Se il thread “stoppato” sta operando in un
monitor (su dati critici, e.g. conto corrente
bancario) allora, per effetto di uno stop, il
monitor può finire in uno stato inconsistente
(e.g. si è versato un deposito in cassa ma non
ancora sul cc del correntista).
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
26
Controllo esecuzione in Java2
Metodo statico (di classe) Thread.yield()
– L’invocazione di tale metodo porta lo stato del
thread corrente (non stia eseguendo un metodo
sincronizzato!) da “RUNNING” a “READY” ; un
thread (scelto dallo schedulatore) da “READY”
diviene “RUNNING”.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
27
Thread: syncronized
• Se due o più thread operano sul medesimo oggetto
(istanza), possono originarsi inconsistenze dovute
alla sequenza effettiva di esecuzione.
• Per rendere mutuamente esclusivo l’accesso a un
elemento (e.g. metodo) della medesima istanza è
necessario e sufficiente dichiarare l’elemento
synchronized nella sua classe.
– Effetto: ne viene impedita l’esecuzione concorrente
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
28
(Alcuni) stati di un thread Java
• CREATED: è lo stato di un thread testé creato.
• READY: (o RUNNABLE) vi si perviene da CREATED per
effeto di uno start(), da RUNNING per effetto di
yeld(), da SLEEPING (fuori monitor) per effetto di un
evento di timeElapsed(), da SUSPENDED (se fuori monitor)
per effetto di un resume() (e da JOINING o
INTERRUPTED).
• DEAD: è lo stato di un thread naturalmente o forzatamente
terminato. Vi si perviene quando un thread raggiunge la sua
istruzione di fine o per effetto di un stop() o di un evento
di InterruptedEvent.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
29
(Alcuni) stati di un thread Java
• RUNNING: è lo stato di un thread realmente o virtualmente
in esecuzione. Vi perviene (1) da READY e vi permane
finché (a) non occorre terminazione, (b) non prova ad
accedere a un monitor (enterSynchronizedMethod),
(c) non esegue una yeld() o una sleep(t) (o
interrupt() o join()) (2) da BLOCKED per effetto di
exitSynchronizedMethod di altro thread con
contestuale sua selezione da parte della macchina Java fra
gli eventuali thread nello stesso stato.
• WAITING: un thread vi previene da RUNNING per effto di
una wait() (o wait(t) et similia).
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
30
Alcuni stati di un thread Java
• BLOCKED: un thread vi perviene da (1) WAITING per effetto di una
notifyAll() o di una notify() con contestuale selezione del
thread, da parte della macchina Java (schedulatore), fra gli eventuali
thread che sono nel suo stesso stato; (2) da RUNNING per effetto del
tentativo di accedere a un metodo synchronized di un monitor occupato
(enterSynchronizedMethod).
• JOINING: un thread RUNNING vi perviene da per effetto
dell’esecuzione di una t.join(); (fuori sincronizzazione!!). Quando
t raggingerà lo stato DEAD, il thread JOINING diventerà READY (/
RUNNING al posto del thread terminato).
• SLEEPING: un thread RUNNING vi perviene da per effetto
dell’esecuzione di una sleep(t); (fuori sincronizzazione!!). Poi
ridiventa Ready.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
31
Prorità di un thread Java
• Un thread ha una priorità di default. Questa
può essere modificata tramite
public final void
setPriority(int newPriority) e
conosciuta tramite
public final int getPriority()
• wait può essere priorizzato, wait(p) e,
conseguentemente, sarà priorizzato l’effetto
di notify() e di quant’altro.
2 luglio 2006
URM2 – ING- OOP0304 OL
G. Cantone e A. Lomartire
32