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