I Thread in Java
Thread e Task Multitasking: capacità dei sistemi operativi di eseguire più programmi contemporaneamente. Ciascun programma ha il proprio insieme di variabili, costanti, ecc. Multithreading capacità dei programmi di eseguire, al loro interno, più task (thread) contemporaneamente. Un programma è multithread se il thread principale lancia almeno un thread secondario. I thread condividono le variabili, le classi del programma, lo spazio di indirizzamento, ha execution stack (stack delle chiamate) e program counter (indirizzo prox istruzione) privati. L20_MultiThread 2
Il multithreading è estremamente diffuso (es. browser che caricano più immagini contemporaneamente, o più pagine), la gestione delle richieste concorrenti da parte di un web service o un application server. Lo stesso meccanismo di garbage collecting è svolto tramite un thread Con JAVA 5 la gestione dei thread è stata completamente rivista ed arricchita, soprattutto dal punto di vista del sincronismo. Java offre degli strumenti che facilitano l'utilizzo dei thread, rispetto ad altri linguaggi di programmazione. L20_MultiThread 3
I thread sono caratterizzati dal loro stato ESECUZIONE PRONTO PER L'ESECUZIONE: in attesa di essere eseguito dalla CPU SOSPESO RIPRESO dal punto in cui era stato sospeso BLOCCATO quando attende una risorsa; TERMINATO L20_MultiThread 4
La priorità dei thread La priorità del thread stabilisce l importanza del trhead rispetto gli altri. La CPU privilegia il thread a maggiore priorità quando deve assegnare tempo di esecuzione ai vari thread. Un thread a priorità più alta può anche terminare un thread a priorità più bassa Il thread principale. Un programma Java possiede un thread di esecuzione, che è il thread principale. In esso si generano gli altri thread per i programmi multithread. Quando il thread thread principale termina, lo stesso programma termina. L20_MultiThread 5
Scheduling dei thread La JVM determina il tempo di esecuzione di ciascun thread con l'algoritmo FIXED PRIORITY SCHEDULING Un thread in esecuzione viene interrotto dallo scheduler quando: Un thread con priorità più alta diventa runnable; Il metodo run termina l esecuzione o il thread esegue un yield; Quando la porzione di tempo (quanto) di tempo assegnato dallo scheduler si è esaurito (non tutti i sistemi operativi - devono supportare il time slicing ) L20_MultiThread 6
Creazione di un thread in Java Java offre due possibilità di creazione di un thread: una istanza di un oggetto che estende l oggetto thread (package java.lang.*). una istanza di un oggetto che implementa l interfaccia runnable L20_MultiThread 7
Primo caso: sottoclasse di Thread Il codice del thread (il task del thread) deve essere inserito nel metodo run Nella classe Thread l implementazione del suo metodo run è vuota. Per attivare il thread si invoca il metodo start() che a sua volta invoca il metodo run() (che può essere chiamato solo attraverso start()) L20_MultiThread 8
class MyThread extends Thread { public MyThread(String str) { super(str); public void run() { for (int i=0;i<10;i++) { System.out.println(getName()+"it: "+i); try { sleep((int)(math.random() * 1000)); catch (InterruptedException e) { System.out.println(getName()+" finito!"); public class test { public static void main (String[] args) { MyThread t1=new MyThread("uno"); MyThread t2=new MyThread("due"); t1.start();//attivazione del thread t1 t2.start();//attivazione del thread t2 //= QUANTI THREAD CONCORRENTI COESISTONO in questo esempio? L20_MultiThread 9
Metodi della classe Thread resume run sleep(ms) start stop join suspend Riprende l esecuzione di un thread sospeso Contiene il codice eseguibile del tread Sospende il thread per un tempo definito di ms millesecondi Avvia il thread invocando il codice di esecuzione Forza la terminazione ell esecuzione di un thread. Tutte le risorse del thread vengono liberate (anche i lock), attraverso la propagazione dell eccezione ThreadDeath blocca il thread chiamante in attesa della terminazione del thread di cui si invoca il metodo. Sospente indefinatemente il thread L20_MultiThread 10
Interrompere un Thread Un thread termina quando il suo metodo run termina. Il metodo stop() per la terminazione forzata e stato deprecato, per scoraggiarne l'uso (evitare che il thread non rilasci risorse, ecc). Il metodo interrupt è usato per richedere la terminazione di un Thread, che viene messo nello stato interrupted I thread dovrebbero di tanto in tanto controllare se sono in uno stato interrupted. L20_MultiThread 11
Lo stato interrupted non è una richiesta mandatoria di terminazione, ma va interpretato caso per caso (verifica altre condizioni chiusura), ecc TIPICA IMPLEMENTAZIONE public void run() { try { //== while (!Thread.currentThread().isInterrupted() && more work to do) { do more work catch(interruptedexception e) { // thread was interrupted during sleep or wait finally { cleanup, if required // exiting the run method terminates the thread L20_MultiThread 12
Il metodo sleep solleva la InterruptedException se viene invocato quando è in uno strato interrupted. In questo caso non c'è bisogno di considerare lo stato Interrupted public void run() { try {... while (more work to do) { do more work Thread.sleep(delay); catch(interruptedexception e) { // thread was interrupted during sleep or wait finally { cleanup, if required // exiting the run method terminates the thread L20_MultiThread 13
Altri metodi interrupt() static boolean interrupted() boolean isinterrupted() currentthread() Mette il trhead nello stato booleano interrupt Verifica che il thread è stato messo in uno stato interrupted. L invocazione del metodo resetta lo stato interrupted a false Verifica che il thread è stato messo in uno stato interrupted. L invocazione del metodo NON resetta lo stato interrupted Restituisce il thread corrente (statico) L20_MultiThread 14
Il thread principale Il metodo currentthread restituisce il riferimento al thread corrente. Se lanciato all interno del programma principale da il riferimento al thread principale public class MainThread { public static void main(string args[]) { Thread t = Thread.currentThread(); t.setname( Main Thread"); t.setpriority(1); try { t.sleep(10000); catch (InterruptedException e) { System.out.println("Thread interrotto"); L20_MultiThread 15
L interfaccia runnable Con Interfaccia Runnable è possibile creare thread come sottoclasse di qualsiasi altra classe (non solo di Thread) Il codice eseguibile va inserito nel metodo run() nella classe che implementa l interfaccia Runnable Si deve creare un istanza della classe Si deve creare un istanza della classe Thread passando come parametro l istanza della classe che si è creata Per lanciare il thread si deve invocare il metodo start() sul thread creato producendo la chiamata al metodo run() L20_MultiThread 16
class MyRunnable extends MyClass implements Runnable { // MyClass è una classe qualsiasi (non sottoclasse di thread) public void run() { for (int i=1; i<=100; i++) System.out.println( CICLO + i); public class ExRunnable { public static void main(string args[]) { MyRunnable e = new MyRunnable(); Thread t = new Thread(e); t.start(); L20_MultiThread 17
Thread e priorità L assegnazione delle risorse da parte della JVM avviene secondo un schema preemptive, in base alla priorità dei thread. Ciascun thread eredita la priorità dei thread genitore. La priorità si può cambiare tramite il metodo setpriority La priorità varia tra MIN_PRIORITY o MAX_PRIORITY L20_MultiThread 18
La sincronizzazione In molte situazioni, i thread devono condividere risorse ed accedere agli stessi oggetti. Accedendo contemporaneamente agli stessi oggetti, due o più thread possono procurare effetti incontrollati sullo stato degli oggetti L20_MultiThread 19
Allo stesso modo i metodi stop() e suspend() dei thread possono generare situazioni iconsistenti o blocchi critici. I Thread possono, all atto della sospensione impegnare una risorsa in modo esclusivo, generando situazioni inconsistenti o di blocco critico (deadlock) L20_MultiThread 20
A partire dalla JDK vers. 1.4, i metodi stop(), suspend() e resume() sono diventati deprecated (sconsigliati), pur rimanendo presenti per retro compatibilità. Le azioni di controllo e sincronizzazione fra thread si devono più propriamente realizzare tramite i metodi wait(), notify(), notifyall() e gli object locks. L20_MultiThread 21
I thread condividono uno spazio comune di indirizzamento, e l interazione può avvenire tramite oggetti comuni, che sono: 1)Object locks -> i thread si autoescludono (interazione competitiva) 2)Variabili 3)Metodi di sincronizzazione -> interazione cooperativa L20_MultiThread 22
Lock I thread gestiscono le risorse comuni attraverso i lock assimilabili ai semafori del C. Si individuano alcune sezioni di codice che operano su un oggetto come sezioni critiche (la parola chiave synchronized). Il compilatore, in corrispondenza della sezione critica inserisce una intestazione (header), ed un epilogo (alla fine), in questo modo implementa il lock associato all oggetto riferito dalla sezione critica L20_MultiThread 23
Esempio: Object mutex_lock= new Object(); public void A( ) { ; synchronized (mutex_lock){ /* codice sezione critica */; ; Il codice della sezione critica viene eseguito se il lock è in stato libero, altrimenti il thread rimane in attesa. Gli oggetti che vogliono accede all oggetto, sono inseriti in una tabella dalla JVM, e via via accedono all oggetto non appena viene rilasciato dai vari thread L20_MultiThread 24
Il codice della blocco sincronizzato viene eseguito in maniera esclusiva da un thread Non ci possono essere altre esecuzioni dello stesso blocco Non ci possono essere esecuzione di altri blocchi sincronizzati sullo stesso oggetto L20_MultiThread 25
Metodi synchronized E possibile definire alcuni metodi sincronized, assicurandone la loro mutua esclusione public class intvar { private int i=0; public synchronized void incrementa() { i ++; public synchronized void decrementa() {i--; L esecuzione del metodo avviene in mutua esclusione utilizzando il lock dell oggetto. L20_MultiThread 26
I metodi wait e notify La sincronizzazione tra i thread puo avvenire anche con i metodi wait e notify I metodi wait interagiscono con il wait set, coda di thread associati ad un oggetto Gli oggetti entrano ed escono nel wait set con i metodi wait e notify, che possono essere invocati all interno di un blocco syncronized L20_MultiThread 27
wait rilascia il lock, sospende il e lo inserisce in wait set. notify Estrae il thread dal wait set e lo inserisce nel entry set. NON RILASCIA IL LOCK notifyall LIMITAZIONI Estrae tutti i thread dal wait set e li inserisce nell entry set NON rilascia il lock unica coda (wait set) per ogni oggetto sincronizzato non e` possibile sospendere thread su code differenti! L20_MultiThread 28
public class IntBox { private int[]contenuto; private int contatore, testa, coda; public IntBox(){ //==ctr contenuto = new int[10]; contatore = 0; testa = 0; coda = 0; public synchronized int preleva (){ int elemento; while (contatore == 0) wait(); elemento = contenuto[testa]; testa = (testa + 1)%10; --contatore; notifyall(); return elemento; public synchronized void deposita (int valore){ while (contatore == 10) wait(); contenuto[coda] = valore; coda = (coda + 1)%10; ++contatore; notifyall(); L20_MultiThread 29
Implementazione di un semaforo binario Java non prevede i semafori come nel C, ma possono essere implementati con i metodi di sincronizzazione public class Semaphore { private int value; public Semaphore (int initial){ value = initial; synchronized public void V()//signal sul semaforo { ++value; notify(); synchronized public void P() throws InterruptedException //wait { { while (value == 0) wait(); --value; L20_MultiThread 30
Interfaccia Condition In Java 5 sono state introdotte le interface condition e lock che permettono di estendere il meccanismo wait/notify e di esplicitare il lock public interface Condition{ void await ()throws InterruptedException; void signal(); void signalall(); public interface Lock{ //Public instance methods void lock(); void unlock(); Condition newcondition(); I metodi await, signal, e signalall sono equivalenti ai metodi wait, notify e notify_all, riferiti alla coda di processi associata alla condition sulla quale vengono invocati) L20_MultiThread 31
Ad ogni variabile condizione è associato un lock al momento della sospensione del thread mediante await viene liberato; al risveglio di un thread viene occupato. La creazione di una condition avviene col metodo newcondition del lock associato ad essa. Lock lockvar=new Mylock(); //Mylock è una classe che implementa //l interfaccia Lock Condition C=lockvar.newCondition(); L20_MultiThread 32
Equivalenza tra meccanismo lock e syncronized public void method() { implicitlock.lock(); try { //method body finally { implicitlock.unlock(); public synchronized void method() { //method body /*(es)*/ L20_MultiThread 33
DeadLock Possono verificarsi delle situazioni applicative in cui la concorrenza dei thread può bloccare l'elaborazione. E' il caso in cui un thread entra in una sezione critica di un metodo A, al cui interno c'è' l'invocazione di un metodo sincronizzato B, che a sua volta invoca il metodo A. Due thread che accedono al metodo A e B possono mutuamente bloccarsi, perché aspettano l'uscita dell'altro dalla sezione critica Non c'è un meccanismo effettivo per evitare i deadlock, né strumenti offerti da Java. Si devono escludere possibili situazioni di deadlock applicativamente L20_MultiThread 34
Blocking Queue Le blocking queue sono code tipo FIFO speciali con le due operazioni fondamentali (aggiungere un elemento in coda e rimuovere quello in testa), con la proprietà di bloccare i thread che vi accedono per aggiungere elementi quando la coda è piena, o quando cercano di rimuovere e la coda è vuota. In questo modo si dispone di un meccanismo di sincronizzazione dei thread e di bilanciamento del carico tra i therad L20_MultiThread 35
Metodi di blockqueue metodo Ok KO add Aggiunge un elemento alla lista Eccezione IllegalStateException se la coda è piena remove Rimuove e restituisce l'elemento top della lista Eccezione NoSuchElementException se la coda è vuota element Restituisce l'elemento top della lista Eccezione NoSuchElementException se la coda è vuota offer poll Aggiunge un elemento e restituisce true Rimuove e restituisce l'elemento top della lista Restituisce null se la coda è piena Restituisce null se la coda è vuota peek Restituisce l'elemento top della lista Restituisce null se la coda è vuota put Aggiunge un elemento alla lista Blocca la coda se è piena take Rimuve e restituisce l'elemento top Blocca la coda se è vuota della lista L20_MultiThread 36
Thread safe collection Quando due thread contemporaneamente accedono ad una collection, possono danneggiare la collection, produrre stati inconsistenti. E' possibile richiedere l'accesso esclusivo con dei meccanismi di sincronizzazione Il package java.util.concurrent offre delle efficienti implementazioni di collection che thread safe, che consentono a diversi thread di accedere contemporaneamente alla struttura (fino a 16) L20_MultiThread 37
L'effetto si ottiene attraverso sofisticati algoritmi che regolano l'accesso ed iteratori di tipo weak che possono non tenere conto delle ultime modifiche alla struttura Esempio: ConcurrentHashMap L20_MultiThread 38
Interfacce Callable e Future L'interfaccia callable è simile alla Runnable solo che prevede che venga restituito un valore public interface Callable<V> { V call() throws Exception; L'interfaccia Future puo' essere usata per lanciare una computazione (asincrona), ed ottenere il risultato successivamente public interface Future<V> { V get() throws...; V get(long timeout, TimeUnit unit) throws...; void cancel(boolean mayinterrupt); boolean iscancelled(); boolean isdone(); L20_MultiThread 39
Thread Pools Java fornisce dei meccanismi (classi Executors) per gestire thread pool. In questo modo il numero di thread creati è controllato (con minore dispendio di risorse) newfixedthreadpool Pool di thread fisso e mantenuti in idle indefinitamente. newcachedthreadpool I thread sono creati quando necessario, e mantenuti in idle per 60 sec. newsinglethreadexecutor Un pool costituito da un solo thread che svolge i supoi compiti sequenzialmente newscheduledthreadpool Pool fisso per esecuzioni schedulate newsinglethreadscheduledexecutor Single thread per l'esecuzione schedulata L20_MultiThread 40
Syncronizers Il package java.util.concurrent dispone di una serie di oggetti specializzati nella sincronizzazione classe Cosa fa Quando usarla CyclicBarrier CountDownLatch Exchanger SynchronousQueue Semaphore Fa in modo che un certo numero di thread aspettano il compimento delle azioni di tutti gli altri, quindi esegue una azione opzionale (barrier action) Mette in attesa un set di thread fino a che un contatore raggiunge il valore 0 Fa in modo che due thread si scambino un oggetto quando sono pronti per farlo Fare in modo che due thread possono scambiarsi degli oggetti, quando entrambi sono pronti per farlo. Quando un thread invoca put sulla coda, si blocca fino a che un altro thread invoca take Quando è necessario aspettare che i thread abbiamo finito la loro azione per passare alla successiva Quando è necessario che un tread aspetti un certo risultato per entrare in azione Quando due trhead devono condividere una istanza modificando i suoi valori A differenza di exchanger, lo scambio dati è unidirezionale Blocca i thread fino a che è possibile Agendo sul numero di permit, consente di procedere limitare l'accesso a risorse ad un numero di thread alla volta Se permit =1 l'accesso è consentito solo se un altro thread ad il L20_MultiThread permesso 41