Università degli Studi di Pisa Dipartimento di Informatica Laboratorio di Reti Lezione 1 JAVA Thread Programming: Introduzione, ThreadPooling 27/09/2016 Laura Ricci U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 1 INFORMAZIONI UTILI • Riferimenti Laura Ricci ([email protected]), Damiano Di Francesco Maesa (supporto alla didattica) • Orario del Corso: martedì 9.00-11.00 : lezione aula C1 martedì 14.00-16.00 : laboratorio aula H • Ricevimento: giovedì ore 15.00-18.00, nel mio studio, in qualsiasi momento per e-mail • Moodle https://elearning.di.unipi.it/moodle/, pagina del corso pubblicazione contenuti forum,chats... assignments test U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 2 INFORMAZIONI UTILI • esperienze pratiche in laboratorio obiettivo: verifica esercizi assegnati nelle lezioni teoriche bonus per esame se si consegna l'esercizio entro 15 giorni dalla data di assegnazione. • modalità di esame: l’esame finale di Reti Calcolatori e Laboratorio: progetto + prova scritta + orale. Il progetto deve essere consegnato almeno una settimana prima della data della prova scritta. si può accedere allo scritto se e solo se il progetto ha ricevuto una valutazione sufficiente. per accedere alla prova orale conclusiva è necessario ottenere una valutazione sufficiente del progetto e superare la prova scritta. orale modulo laboratorio di reti : discussione del progetto + domande sugli tutti argomenti trattati nelle lezioni teoriche il progetto verrà consegnato in all’inizio di dicembre e rimarrà valido fino a settembre 2017. U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 3 INFORMAZIONI UTILI Prerequisiti: • corso di Programmazione 2, conoscenza del linguaggio JAVA: in particolare: packages gestione delle eccezioni collezioni generics • modulo di reti: conoscenza TCP/IP Linguaggio di programmazione di riferimento: JAVA 8 concorrenza: costrutti base, JAVA.UTIL.CONCURRENT JAVA.NIO collezioni rete: JAVA.NET, JAVA.RMI Ambiente di sviluppo di riferimento: Eclipse U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 4 INFORMAZIONI UTILI • Materiale Didattico: lucidi delle lezioni per la parte relativa ai threads Bruce Eckel – Thinking in JAVA – Volume 3 - Concorrenza e Interfacce Grafiche B. Goetz, JAVA Concurrency in Practice, 2006 Per la parte relativa alla programmazione di rete Dario Maggiorini Introduzione alla Programmazione Client Server, Pearson Esmond Pitt Fundamental Networking in JAVA • Materiale di Consultazione: Harold, JAVA Network Programming 3nd edition O'Reilly 2004. K.Calvert, M.Donhaoo, TCP/IP Sockets in JAVA, Practical Guide for Programmers Costrutti di base Horstmann ,Concetti di Informatica e Fondamenti di Java 2 U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 5 PROGRAMMA PRELIMINARE DEL CORSO Threads creazione ed attivazione di threads, Callable: threads che restituiscono i risultati, interruzioni meccanismi di gestione di pools di threads mutua esclusione, lock implicite ed esplicite il concetto di monitor: sincronizzazione di threads su strutture dati condivise: synchronized, wait, notify, notifyall concurrent collections Stream ed IO Streams: tipi di streams, composizione di streams meccanismi di serializzazione serializzazione standard di JAVA: problemi JSON U continua.... Dipartimento di Informatica Università degli Studi di Pisa JAVA Threads: Introduzione, Thread Pooling Laura Ricci 6 PROGRAMMA PRELIMINARE DEL CORSO Programmazione di rete a basso livello ● connection oriented Sockets ● connectionless sockets: UDP, multicast HTTP e servizi web Non blocking IO Oggetti Distribuiti definizione di oggetti remoti il meccanismo di Remote Method Invocation in JAVA dynamic code loading problemi di sicurezza il meccanismo delle callbacks U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 7 IL CAMMINO FINO A JAVA 8 U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 8 IL CAMMINO FINO A JAVA 8 U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 9 IN QUESTO CORSO: CLASSI IN BLU • 1.0.2 prima versione stabile, rilasciata il 23 gennaio del 1996 AWT Abstract Window Tollkit, applet Java.lang (supporto base per concorrenza), Java.io, Java.util Java.net (socket TCP ed UDP, Indirizzi IP, ma non RMI) • 1.1: RMI, Reflections,.... • 1.2: Swing (grafica), RMI-IIOP, … • 1.4: regular expressions, assert, NIO, IPV6 • JAVA 5: una vera rivoluzione generics, concorrenza,.... • 7: acquisizione da parte di Oracle: framework fork and join • 8: Lambda Expressions U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 10 CONCURRENT PROGRAMMING: MOTIVAZIONI ● concurrent programming: una storia iniziata molti anni fa, recentemente diventata un “hot topic” ● legge di Moore (Gordon Moore, cofondatore di INTEL): https://it.wikipedia.org/wiki/Legge_di_Moore "the number of transistors that can be fit onto a square inch of silicon doubles every 12 months with a reduction of the clock speed" ● “Multicore crisis”: non aumento della frequenza di clock, ma riprogettazione dei processori per contenere non uno ma più core sullo stesso chip come distribuire il carico tra i diversi core? nuovi linguaggi: Scala, Akka, nuove librerie di JAVA,GO,... nuove metodologie di sviluppo del software U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 11 JAVA UTIL.CONCURRENCT FRAMEWORK • JAVA < 5 built in for concurrency: lock implicite, wait, notify e poco più. • JAVA.util.concurrency: lo scopo è lo stesso del framework java.util.Collections: un toolkit general purpose per lo sviluppo di applicazioni concorrenti. no more “reinventing the wheel”! • definire un insieme di utility che risultino: standardizzate facili da utilizzare e dacapire high performance utili in un grande insieme di applicazioni per un vasto insieme di programmatori, da quelli più esperti a quelli meno esperti. U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 12 JAVA UTIL.CONCURRENT FRAMEWORK • sviluppato in parte da Doug Lea, disponibile ,come insieme di librerie JAVA non standard prima della integrazione in JAVA 5.0. • tra i package principali: java.util.concurrent • Executor, concurrent collections, semaphores,... java.util.concurrent.atomic • AtomicBoolean, AtomicInteger,... java.util.concurrent.locks • Condition • Lock • ReadWriteLock U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 13 JAVA 5 CONCURRENCT FRAMEWORK U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 14 THREAD: DEFINIZIONE • Processo: programma in esecuzione esempio: se mando in esecuzione due diverse applicazioni, ad esempio MS Word, MS Access, vengono creati due processi • Thread (light weight process: un flusso di esecuzione all’interno di un processo • multitasking, si può riferire a thread o processi a livello di processo è controllato esclusivamente dal sistema operativo a livello di thread è controllato, almeno in parte, dal programmatore U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 15 PROCESSI E THREADS Thread verso process multitasking: i thread condividono lo stesso spazio degli indirizzi meno costoso il cambiamento di contesto tra thread la comunicazione tra thread wsecuzione dei thread: single core: multiplexing, interleaving (meccanismi di time sharing,...) multicore: più flussi in esecuzione eseguiti in parallelo, simultaneità di esecuzione U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 16 MULTITHREADING: PERCHE’? ● ● Struttura di un browser: ● visualizza immagini sullo schermo ● controlla input dalla keyboard e da mouse ● invia e ricevi dati dalla rete ● leggi e scrivi dati su un file ● esegui computazione (editor, browser, game) come gestire tutte queste funzionalità simultaneamente? una decomposizione del programma in threads implica: ● ● modularizzazione della struttura dell’applicazione ● aumento della responsiveness altre applicazioni complesse che richiedono la gestione contemporanea di più attività ad esempio: applicazioni interattive distribuite come giochi multiplayers ● interazione con l'utente + messaggi da altri giocatori (dalla rete...) U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 17 MULTITHREADING: PERCHE’? ● Cattura la struttura della applicazione ● molte componenti interagenti ● ogni componente gestita da un thread separato ● semplifica la programmazione della applicazione U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 18 MULTITHREADING: PERCHE’? ● struttura di un server sequenziale ● ogni client deve aspettare la terminazione del servizio della richiesta precedente ● ● responsiveness limitata struttura di un server multithreaded ● un insieme di worker therad per ogni client ● aumento responsiveness U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 19 MULTITHREADING: PERCHE’? • Migliore utilizzazione delle risorse quando un thread è sospeso, altri thread vengono mandati in esecuzione riduzione del tempo complessivo di esecuzione • Migliore performance per computationally intensive application dividere l’applicazione in task ed eseguirli in parallelo • Tanti vantaggi, ma anche alcuni problemi: più difficile il debugging e la manutenzione del software rispetto ad un programma single threaded race conditions, sincronizzazioni deadlock, livelock, starvation,... U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 20 CREAZIONE ED ATTIVAZIONE DI THREAD • quando si manda in esecuzione un programma JAVA, la JVM crea un thread che invoca il metodo main del programma: almeno un thread per ogni programma • altri thread sono attivati automaticamente da JAVA (gestore eventi, interfaccia, garbage collector,...). • ogni thread durante la sua esecuzione può creare ed attivare altri threads. • come ogni cosa in JAVA, un thread è un oggetto. Come creare ed attivare un thread? definire un task, ovvero definire una classe C che implementi l'interfaccia Runnable, creare una istanza di C, quindi creare un thread passandogli l’istanza del task creato estendere la classe java.lang.Thread U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 21 RUNNABLE INTERFACE • appartiene al package java.language contiene solo la segnatura del metodo void run() • una classe C che implementa l'interfaccia deve fornire un'implementazione del metodo run() • un oggetto istanza di C è un task: un fragmento di codice che può essere eseguito in un thread la creazione del task non implica la creazione di un thread per lo esegua. lo stesso task può essere eseguito da più threads: un solo codice, più esecutori • un oggetto Thread viene istanziato con un riferimento al task da eseguire U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 22 ATTIVAZIONE DI THREADS: UN ESEMPIO • Scrivere un programma che stampi le tabelline moltiplicative dall' 1 al 10 si attivino 10 threads ogni numero n, 1 n 10, viene passato ad un thread diverso il task assegnato ad ogni thread consiste nello stampare la tabellina corrispondente al numero che gli è stato passato come parametro U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 23 IL TASK CALCULATOR public class Calculator implements Runnable { private int number; public Calculator(int number) { this.number=number } public void run() { for (int i=1; i<=10; i++){ System.out.printf("%s: %d * %d = %d\n", Thread.currentThread().getName(),number,i,i*number); }}} • NOTA: public static native Thread currentThread ( ): più thread potranno eseguire il codice di Calculator qual'è il thread che sta eseguendo attualmente questo codice? CurrentThread() restituisce un riferimento al thread che sta eseguendo il segmento di codice all'interno del quale si trova la sua invocazione U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 24 IL MAIN PROGRAM public class Main { public static void main(String[] args) { for (int i=1; i<=10; i++){ Calculator calculator=new Calculator(i); Thread thread=new Thread(calculator); thread.start();} System.out.println("Avviato Calcolo Tabelline"); } } L'Output Generato dipende dalla schedulazione effettuta, un esempio è il seguente: Thread-0: 1 * 1 = 1 Thread-9: 10 * 1 = 10 Thread-5: 6 * 1 = 6 Thread-8: 9 * 1 = 9 Thread-7: 8 * 1 = 8 Thread-6: 7 * 1 = 7 Avviato Calcolo Tabelline Thread-4: 5 * 1 = 5 Thread-2: 3 * 1 = 3 U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 25 ALCUNE OSSERVAZIONI ● Output generato (dipendere comunque dallo schedulatore): Thread-0: 1 * 1 = 1 Thread-9: 10 * 1 = 10 Thread-5: 6 * 1 = 6 Thread-8: 9 * 1 = 9 Thread-7: 8 * 1 = 8 Thread-6: 7 * 1 = 7 Avviato Calcolo Tabelline Thread-4: 5 * 1 = 5 Thread-2: 3 * 1 = 3 • da notare: il messaggio Avviato Calcolo Tabelline è stato visualizzato prima che tutti i threads completino la loro esecuzione. Perchè? il controllo ripassa al programma principale, dopo la attivazione dei threads e prima della loro terminazione. U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 26 METODO START( ) VERSO METODO RUN( ) public class Main { public static void main(String[] args) { for (int i=1; i<=10; i++){ Calculator calculator=new Calculator(i); Thread thread=new Thread(calculator); thread.run();} System.out.println("Avviato Calcolo Tabelline"} } Output generato main: 1 * 1 = 1 main: 1 * 2 = 2 main: 1 * 3 = 3 …...... main: 2 * 1 = 2 main: 2 * 2 = 4 …...... Avviato Calcolo Tabelline U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 27 START E RUN • non si crea un nuovo flusso di esecuzione (attivazione del thread) se: si crea un oggetto istanza della classe Thread() si invoca il metodo run() della classe che implementa l'interfaccia Runnable solo il metodo start() comporta la creazione di un nuovo thread()! • cosa accade se sostituisco l'invocazione del metodo run alla start? non viene attivato alcun thread ogni metodo run() viene eseguito all'interno del flusso del thread attivato per l'esecuzione del programma principale flusso di esecuzione sequenziale il messaggio “Avviato Calcolo Tabelline” viene visualizzato dopo l'esecuzione di tutti i metodi metodo run() quando il controllo torna al programma principale U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 28 ATTIVAZIONE DI THREADS: RIEPILOGO Per definire tasks ed attivare threads che li eseguano definire una classe R che implementi l' interfaccia Runnable, cioè implementare il metodo run. In questo modo si definisce un oggetto runnable, cioè un task che può essere eseguito allocare un'istanza T di R Per costruire il thread, utilizzare il costruttore public Thread (Runnable target) passando il task T come parametro attivare il thread con una start() come nell'esempio precedente. U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 29 ATTIVAZIONE DI THREADS Il metodo start( ) • segnala allo schedulatore (tramite la JVM) che il thread può essere attivato (invoca un metodo nativo). L'ambiente del thread viene inizializzato • rstituisce immediatamente il controllo al chiamante, senza attendere che il thread attivato inizi la sua esecuzione. NOTA: la stampa del messaggio “Avviato Calcolo Tabelline” precede quelle effettuate dai threads. Questo significa che il controllo è stato restituito al thread chiamante (il thread associato al main) prima che sia iniziata l'esecuzione dei threads attivati U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 30 THREAD DEMONI • i thread demoni sono thread che hanno il compito di fornire un servizio in background fino a che il programma è in esecuzione, ma non sono intesi come parte fondamentale del programma • quando tutti i thread non-demoni sono completati, il programma termina (anche se si sono thread demoni in esecuzione) • se ci sono thread non-demoni ancora in esecuzione, il programma non termina • un esempio di thread non-demone è il main() U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 31 THREAD DEMONI public class SimpleDaemons implements Runnable { public SimpleDaemons() { } public void run() { while(true) { try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e);} System.out.println("termino"); }} public static void main(String[] args) { for(int i = 0; i < 10; i++){ SimpleDaemons sd=new SimpleDaemons(); Thread t= new Thread (sd); t.setDaemon(true); t.start();} } } Perchè non viene stampato alcun messaggio “termino”? U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 32 TERMINAZIONE DI PROGRAMMI CONCORRENTI Per determinare la terminazione di un programma JAVA: • un programma JAVA termina quando terminano tutti i threads non demoni che lo compongono • se il thread iniziale, cioè quello che esegue il metodo main( ) termina, i restanti thread ancora attivi continuano la loro esecuzione, fino alla loro terminazione. • se uno dei thread usa l'istruzione System.exit() per terminare l'esecuzione, allora tutti i threads terminano la loro esecuzione U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 33 IL CLASSE THREAD La classe java.lang.Thread contiene metodi per: • costruire un thread interagendo con il sistema operativo ospite • attivare, sospendere, interrompere i threads • non contiene i metodi per la sincronizzazione tra i thread. Questi metodi sono definiti in java.lang.object, perchè la sincronizzazione opera su oggetti Costruttori: • diversi costruttori che differiscono per i parametri utilizzati nome del thread, gruppo a cui appartine il thread,...(.vedere le API) Metodi • possono essere utilizzati per interrompere, sospendere un thread, attendere la terminazione di un thread + un insieme di metodi set e get per impostare e reperire le caratteristiche di un thread esempio: assegnare nomi e priorità ai thread U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 34 IL CLASSE THREAD La classe java.lang.Thread contiene metodi per • porre un thread allo stato blocked: public static native void sleep (long M) sospende l'esecuzione del thread, per M millisecondi. durante l'intervallo di tempo relativo alla sleep, il thread può essere interrotto metodo statico: non può essere invocato su una istanza di un thread U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 35 GESTIRE LE INTERRUZIONI • JAVA mette a disposizione un meccanismo per interrompere un thread e diversi meccanismi per intercettare l'interruzione dipendenti dallo stato in cui si trova un thread, running, blocked il thread decide interruzione comunque autonomamente come rispondere alla • un thread può essere interrotto e può intercettare l'interruzione in modi diversi, a seconda dello stato in cui si trova se è sospeso l'interruzione InterruptedException causa il sollevamento di una se è in esecuzione, può testare un flag che segnala se è stata inviata una interruzione. U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 36 GESTIONE DI INTERRUZIONI Intercettare una interruzione quando il thread è sospeso public class SleepInterrupt implements Runnable {public void run ( ){ try{System.out.println("dormo per 20 secondi"); Thread.sleep(20000); System.out.println ("svegliato");} catch ( InterruptedException x ) { System.out.println("interrotto");return;}; System.out.println("esco normalmente");} } se esiste un interrupt pendente al momento dell'esecuzione della sleep(), viene sollevata immediatamenete una InterruptedException. U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 37 GESTIONE DELLE INTERRUZIONI public class SleepMain { public static void main (String args [ ]) { SleepInterrupt si = new SleepInterrupt(); Thread t = new Thread (si); t.start ( ); try {Thread.sleep(2000);} catch (InterruptedException x) { }; System.out.println("Interrompo l'altro thread"); t.interrupt( ); System.out.println ("sto terminando..."); } } U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 38 INTERROMPERE UN THREAD • implementazione del metodo interrupt(): imposta a true un valore booleano nel descrittore del thread. • il flag vale true se esistono interrupts pendenti • è possibile testare il valore del flag mediante: public static boolean Interrupted ( ) (metodo statico, si invoca con il nome della classe Thread.Interrupted( )) public boolean isInterrupted ( ) deve essere invocato su un'istanza di un oggetto di tipo thread entrambi i metodi restituiscono un valore booleano che segnala se il thread ha ricevuto un'interruzione riportano il valore del flag a false U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 39 STATI DI UN THREAD U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 40 UN THREAD PER OGNI TASK: SVANTAGGI Svantaggi della soluzione un thread per ogni task: • thread Life Cycle Overhead overhead per la creazione/distruzione dei threads che richiede una interazione tra la JVM ed il sistema operativo varia a seconda della piattaforma, ma non è mai trascurabile per richieste di servizio frequenti e 'lightweight' può impattare negativamente sulle prestazioni dell' applicazione • resource consumption molti threads idle quando il loro numero supera il numero di processori disponibili. Alta occupazione di risorse (memoria,....) sia il garbage collector che lo schedulatore sono 'sotto stress' • stability limitazione al numero di threads imposto dalla JVM/dal SO U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 41 THREAD POOL: MOTIVAZIONI • un thread per ogni task risulta una soluzione improponibile, specialmente nel caso di lightweight tasks molto frequenti. • esiste un limite oltre il quale non risulta conveniente creare ulteriori threads • obiettivi: definire un limite massimo per il numero di threads che possono essere attivati concorrentemente in modo da; sfruttare al meglio i processori disponibili evitare di avere un numero troppo alto di threads in competizione per le risorse disponibili diminuire il costo per l'attivazione/terminazione dei threads U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 42 THREAD POOL: CONCETTI GENERALI • L'utente struttura l'applicazione mediante un insieme di tasks. • Task = segmento di codice che può essere eseguito da un esecutore. in JAVA corrisponde ad un oggetto di tipo Runnable • Thread = esecutore di tasks. • Thread Pool struttura dati la cui dimensione massima può essere prefissata, che contiene riferimenti ad un insieme di threads i thread del pool possono essere riutilizzati per l'esecuzione di più tasks la sottomissione di un task al pool viene disaccoppiata dall'esecuzione del thread. L'esecuzione del task può essere ritardata se non vi sono risorse disponibili U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 43 THREAD POOL: CONCETTI GENERALI • L'utente crea il pool e stabilisce una politica per la gestione dei thread del pool che stabilisce quando i thread del pool vengono attivati: (al momento della creazione del pool, on demand, all'arrivo di un nuovo task,....) se e quando è opportuno terminare l'esecuzione di un thread (ad esempio se non c'è un numero sufficiente di tasks da eseguire) sottomette i tasks per l'esecuzione al thread pool. • Il supporto, al momento della sottomissione del task, può – utilizzare un thread attivato in precedenza, inattivo al momento dell'arrivo del nuovo task – creare un nuovo thread – memorizzare il task in una struttura dati (coda), in attesa di eseguirlo – respingere la richiesta di esecuzione del task • il numero di threads attivi nel pool può variare dinamicamente U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 44 THREADPOOL IN JAVA • implementazione del thread pooling: – fino a J2SE 4 a carico del programmatore – J2SE 5.0 definisce la libreria java.util.concurrent che contiene metodi per • creare un thread pool ed il gestore associato • definire la struttura dati utilizzata per la memorizzazione dei tasks in attesa • definire specifiche politiche per la gestione del pool • il meccanismo introdotto permette una migliore strutturazione del codice poichè tutta la gestione dei threads può essere delegata al supporto U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 45 THREADPOOL IN JAVA ● alcune interfacce definiscono servizi generici di esecuzione public interface Executor { public void execute (Runnable task) } public interface ExecutorService extends Executor {.......... } diversi servizi che implementano il generico ExecutorService (ThreadPoolExecutor, ScheduledThreadPoolExecutor,..) la classe Executors che opera come una Factory in grado di generare oggetti di tipo ExecutorService con comportamenti predefiniti. i tasks devono essere incapsulati in oggetti di tipo Runnable e passati a questi esecutori, mediante invocazione del metodo execute() U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 46 SOTTOMISSIONE DI TASK AD UN SERVER public class Main { public static void main(String[] args) throws Exception { Server server=new Server(); for (int i=0; i<10; i++){ Task task=new Task("Task "+i); server.executeTask(task); } server.endServer();}} • creazione di un server • sottomissione di una sequenza di task al server. Il server eseguirà i task in modo concorrente utilizzando un thread pool. • terminazione del server U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 47 DEFINIZIONE DI UN SERVER CONCORRENTE import java.util.concurrent.*; public class Server { private ThreadPoolExecutor executor; public Server( ) {executor=(ThreadPoolExecutor)Executors.newCachedThreadPool();} public void executeTask(Task task){ System.out.printf("Server: A new task has arrived\n"); executor.execute(task); System.out.printf("Server:Pool Size:%d\n",executor.getPoolSize()); System.out.printf("Server:Active Count:%d\n",executor.getActiveCount()); System.out.printf("Server:Completed Tasks:%d\n",executor.getCompletedTaskCount()); public void endServer() { executor.shutdown();}} U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 48 NewCachedThreadPool crea un pool con un comportamento predefinito: • se tutti i thread del pool sono occupati nell'esecuzione di altri task e c'è un nuovo task da eseguire, viene creato un nuovo thread. nessun limite sulla dimensione del pool • se disponibile, viene riutilizzato un thread che ha terminato l'esecuzione di un task precedente. • se un thread rimane inutilizzato per 60 secondi, la sua esecuzione termina ● Elasticità: “un pool che può espandersi all'infinito, ma si contrae quando la domanda di esecuzione di task diminuisce” U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 49 UN TASK CHE SIMULA UN SERVIZIO... • in questo e nei successivi esempi, il singolo servizio sarà simulato inserendo delle attese casuali (Thread.sleep( )), per semplicità import java.util.*; public class Task implements Runnable { private String name; public Task(String name){ this.name=name; } U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 50 UN TASK CHE SIMULA UN SERVIZIO... import java.util.*; public class Task implements Runnable { private String name; public Task(String name){ this.name=name;} public void run() { System.out.printf("%s: Task %s \n", Thread.currentThread().getName(),name); try{ Long duration=(long)(Math.random()*10); System.out.printf("%s: Task %s: Doing a task during %d seconds\n", Thread.currentThread().getName(),name,duration); Thread.sleep(duration); } catch (InterruptedException e) {e.printStackTrace();} System.out.printf("%s: Task Finished %s \n", Thread.currentThread().getName(),name);}}} U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 51 OSSERVARE L'OUTPUT: IL RIUSO DEI THREAD Server: A new task has arrived Server: Pool Size: 1 pool-1-thread-1: Task Task 0 Server: Active Count: 1 Server: Completed Tasks: 0 pool-1-thread-1: Task Task 0: Doing a task during 1 seconds Server: A new task has arrived Server: Pool Size: 2 Server: Active Count: 1 pool-1-thread-1: Task Finished Task 0 pool-1-thread-2: Task Task 1 pool-1-thread-2: Task Task 1: Doing a task during 7 seconds Server: Completed Tasks: 0 Server: A new task has arrived Server: Pool Size: 2 pool-1-thread-1: Task Task 2 U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 52 AUMENTARE IL RIUSO import java.util.*; public class Main { public static void main(String[] args) throws Exception{ Server server=new Server(); for (int i=0; i<10; i++){ Task task=new Task("Task "+i); server.executeTask(task); Thread.sleep(5000); } server.endServer();}} La sottomissione di tasks al pool viene distanziata di 5 secondi. In questo modo l'esecuzione precedente è terminata ed il programma riutilizza dempre lo stesso thread. U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 53 AUMENTARE IL RIUSO Server: A new task has arrived Server: Pool Size: 1 pool-1-thread-1: Task Task 0 Server: Active Count: 1 Server: Completed Tasks: 0 pool-1-thread-1: Task Task 0: Doing a task during 6 seconds pool-1-thread-1: Task Finished Task 0 Server: A new task has arrived Server: Pool Size: 1 pool-1-thread-1: Task Task 1 Server: Active Count: 1 pool-1-thread-1: Task Task 1: Doing a task during 2 seconds Server: Completed Tasks: 1 pool-1-thread-1: Task Finished Task 1 U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 54 AUMENTARE IL RIUSO Server: A new task has arrived Server: A new task has arrived Server: Pool Size: 1 pool-1-thread-1: Task Task 2 Server: Active Count: 1 pool-1-thread-1: Task Task 2: Doing a task during 5 seconds Server: Completed Tasks: 2 pool-1-thread-1: Task Finished Task 2 Server: A new task has arrived Server: Pool Size: 1 Server: Active Count: 1 pool-1-thread-1: Task Task 3 U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 55 newFixedThreadPool( ) import java.util.concurrent.*; public class Server { private ThreadPoolExecutor executor; public Server(){ executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(2); } …... newFixedThreadPool(int N) crea un pool in cui: ● ● vengono creati N thread, al momento della inizializzazione del pool, riutilizzati per l'esecuzione di più tasks quando viene sottomesso un task T se tutti i threads sono occupati nell'esecuzione di altri tasks,T viene inserito in una coda, gestita automaticamente dall'ExecutorService la coda è illimitata se almeno un thread è inattivo, viene utilizzato quel thread U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 56 CREAZIONE/ATTIVAZIONE THREADS: METODO 2 ● utilizzare funzionalità dei linguaggi ad oggetti: subclassing, overriding ● creare una classe C che estenda la classe Thread ed effettuare l' overriding del metodo run() definito di quella classe ● ● istanziare un oggetto di quella classe: questo oggetto è un thread il cui comportamento è quello definito nel metodo run su cui è stato fatto l'overriding invocare il metodo start() sull'oggetto istanziato. U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 57 CREAZIONE/ATTIVAZIONE THREADS: METODO 2 public class Calculator extends Thread { ........ public void run() { for (int i=1; i<=10; i++) {System.out.printf("%s: %d * %d = %d\n", Thread.currentThread().getName(),number,i,i*number);}}} public class Main { public static void main(String[] args) { for (int i=1; i<=10; i++){ Calculator calculator=new Calculator(i); calculator.start();} System.out.println("Avviato Calcolo Tabelline"); } } U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 58 INTERAZIONE TRA THREADS: BLOCKING QUEUE BlockingQueue (java.util.concurrent package): una coda “thread safe” per quanto riguarda gli inserimenti e le rimozioni • il produttore può inserire elementi nella coda fino a che la dimensione della coda non raggiunge un limite, dopo di che si blocca e rimane bloccato fino a che un consumatore non rimuove un elemento • il consumatore può rimuovere elementi dalla coda, ma se tenta di eliminare un elemento dalla coda, si blocca fino a che il produttore inserisce un elemento nella coda. U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 59 BLOCKINGQUEUE METHODS AND IMPLEMENTATIONS • 4 metodi differenti, rispettivamente, per inserire, rimuovere, esaminare un elemento della coda, ogni metodo ha un comportamento diverso relativamente al caso in cui l'operazione non possa essere svolta • BlockingQueue è un'interfaccia, alcune implementazioni disponibili: – ArrayBlockingQueue – DelayQueue – LinkedBlockingQueue – PriorityBlockingQueue – SynchronousQueue U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 60 CODE THREAD SAFE: BLOCKINGQUEUE import java.util.concurrent.*; public class BlockingQueueExample { public static void main(String[] args) throws Exception { BlockingQueue queue = new ArrayBlockingQueue(1024); Producer producer = new Producer(queue); Consumer consumer = new Consumer(queue); new Thread(producer).start(); new Thread(consumer).start(); Thread.sleep(4000); } } U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 61 CODE THREAD SAFE: BLOCKINGQUEUE import java.util.concurrent.*; public class Producer extends Thread{ protected BlockingQueue queue = null; public Producer(BlockingQueue queue) { this.queue = queue; } public void run() { try { queue.put("1"); Thread.sleep(1000); queue.put("2"); Thread.sleep(1000); queue.put("3"); } catch (InterruptedException e) { e.printStackTrace(); } } } U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 62 CODE THREAD SAFE: BLOCKINGQUEUE import java.util.concurrent.*; public class Consumer extends Thread { protected BlockingQueue queue = null; public Consumer(BlockingQueue queue) { this.queue = queue; } public void run() { try { System.out.println(queue.take()); System.out.println(queue.take()); System.out.println(queue.take()); } catch (InterruptedException e) { e.printStackTrace(); } } U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 63 BLOCKINGQUEUE IMPLEMENTATIONS • ArrayBlockingQueue è una coda di dimensione limitata, che memorizza gli elementi all'interno di un array. Upper bound definito a tempo di inizializazzione • LinkedBlockingQueue mantiene gli elementi in una struttura linkata che può avere un upper bound, oppure, se non si specifica un upper bound, l'upper bound è Integer.MAX_VALUE. • SynchronousQueue non possiede capacità interna. Operazione di inserzione deve attendere per una corrispondente rimozione e viceversa (un pò fuorviante chiamarla coda). U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 64 ASSIGNMENT 1: CALCOLO DI Scrivere un programma che attiva un thread T che effettua il calcolo approssimato di Il programma principale riceve in input da linea di comando un parametro che indica il grado di accuratezza (accuracy) per il calcolo di ed il tempo massimo di attesa dopo cui il programma principale interomp thread T. Il thread T effettua un ciclo infinito per il calcolo di usando la serie di Gregory-Leibniz ( = 4/1 – 4/3 + 4/5 - 4/7 + 4/9 - 4/11 ...). Il thread esce dal ciclo quando una delle due condizioni seguenti risulta verificata: 1) il thread è stato interrotto 2) la differenza tra il valore stimato di ed il valore Math.PI (della libreria JAVA) è minore di accuracy U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 65 ASSIGNMENT 2: SIMULAZIONE UFFICIO POSTALE • Si vuole simulare il flusso di clienti in un ufficio postale che ha 4 sportelli. Nell'ufficio esiste: – un'ampia sala d'attesa in cui ogni persona può entrare liberamente. Quando entra, ogni persona prende il numero dalla numeratrice e aspetta il proprio turno in questa sala. – una seconda sala, meno ampia, posta davanti agli sportelli, in cui si può entrare solo a gruppi di k persone • Una persona si mette quindi prima in coda nella prima sala, poi passa nella seconda sala. • Ogni persona impiega un tempo differente per la propria operazione allo sportello. Una volta terminata l'operazione, la persona esce dall'ufficio U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 66 ASSIGNMENT 2: SIMULAZIONE UFFICIO POSTALE • Scrivere un programma in cui: – l'ufficio viene modellato come una classe JAVA, in cui viene attivato un ThreadPool di dimensione uguale al numero degli sportelli – la coda delle persone presenti esplicitamente dal programma nella sala d'attesa è gestita – la seconda coda (davanti agli sportelli) è quella gestita implicitamente dal ThreadPool – ogni persona viene modellata come un task, un task che deve essere assegnato ad uno dei thread associati agli sportelli – si preveda di far entrare tutte le persone nell'ufficio postale, all'inizio del programma • Facoltativo: prevedere il caso di un flusso continuo di clienti e la possibilità che l'operatore chiuda lo sportello stesso dopo che in un certo intervallo di tempo non si presentano clienti al suo sportello. U Università degli Studi di Pisa Dipartimento di Informatica JAVA Threads: Introduzione, Thread Pooling Laura Ricci 67