Sei sulla pagina 1di 69

Università degli Studi di Pisa

Dipartimento di Informatica

Laboratorio di Reti - A
Lezione 1
JAVA Thread Programming:
Introduzione, thread pooling

20/09/2018
Laura Ricci

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 1
INFORMAZIONI UTILI
• Docenti

Laura Ricci (laura.ricci@unipi.it),

Andrea Michienzi (supporto alla didattica)

• Orario del Corso


giovedì 9.00 -11.00 : lezione aula A1
giovedì 16.00 -18.00 : laboratorio aula H

• Ricevimento

venerdì ore 14.00-17.00, nel mio studio, in qualsiasi momento per e-mail

• Moodle, sulla 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 orale.

per accedere alla prova orale conclusiva è necessario ottenere una
valutazione sufficiente del progetto.

orale:

discussione del progetto + domande su tutti argomenti trattati nelle
lezioni teoriche di laboratorio

reti: verifica degli argomenti teorici + semplici esercizi

il progetto verrà consegnato in all’inizio di dicembre e rimarrà valido fino a
settembre 2019.

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
• dal modulo teorico 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

Testi consigliati (non obbligatori) per la parte relativa ai threads

Bruce Eckel, Thinking in JAVA - Volume 3 - Concorrenza e Interfacce Grafiche

B. Goetz, JAVA Concurrency in Practice, 2006

Testi consigliati (non obbligatori) 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 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
continua....

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 6
PROGRAMMA PRELIMINARE DEL CORSO

Non blocking IO

Channels, buffers, memory mapped IO


Programmazione di rete a basso livello

connection oriented Sockets

connectionless sockets: UDP, multicast


Non blocking IO e sockets

selectors


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
EVOLUZIONE: CLASSI BLU IN QUESTO CORSO
• 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
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 da capire
 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 11
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 12
JAVA 5 CONCURRENCY FRAMEWORK

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 13
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 14
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

• esecuzione 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 15
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 16
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 17
MULTITHREADING: PERCHE’?

struttura di un server sequenziale:


ogni client deve aspettare la terminazione del servizio della richiesta
recedente

responsiveness limitata


struttura di un server multithreaded


un insieme di worker thread, uno per ogni client

aumento responsiveness

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 18
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 19
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.

• un thread è un oggetto, come ogni entità esistente in JAVA. Come creare ed


attivare un thread?
 definire un task, ovvero definire una classe C che implementi l'interfaccia
Runnable, creare un'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 20
L' INTERFACCIA RUNNABLE

• appartiene al package java.language

• contiene solo la segnatura del metodo void run()

• ogni 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

• quando si istanzia un oggetto Thread, occorre passare un riferimento al task


che il thread deve eseguire

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 21
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 22
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 23
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 24
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 25
METODO START( ) VERSO 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 26
START E RUN
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

 solo il metodo start() comporta la creazione di un nuovo thread()!

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 27
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 28
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.

• restituisce immediatamente il controllo al chiamante, senza attendere che il


thread attivato inizi la sua esecuzione.

 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 29
THREAD DEMONI

• i thread demoni hanno il compito di fornire un servizio in background fino a


che il programma è in esecuzione

 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 30
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 31
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 32
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 33
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 34
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 comunque autonomamente come rispondere alla
interruzione

• 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 causa il sollevamento di una
InterruptedException
 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 35
GESTIONE DI INTERRUZIONI
Intercettare una interruzione quando il thread si sospende

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 in un istante compreso tra l'inizio e la fine della sleep (inizio e fine inclusi), il
flag “interrupted” ha valore vero, allora l'eccezione viene lanciata

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 36
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 37
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 38
STATI DI UN THREAD E OERAZIONI JAVA

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 39
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 40
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 41
THREAD POOLING: 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 42
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 43
JAVA THREADPOOL

Implementazione:

fino a JAVA 4 a carico del programmatore

JAVA 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 44
JAVA THREADPOOL


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 45
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();}}

• simulazione del comportamento di un server (lezioni seguenti vedremo come


sviluppare un vero server che riceve richieste dalla rete).
• 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 46
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 47
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 alla 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 48
UN TASK CHE SIMULA UN SERVIZIO...

• in questo e nei successivi esempi, il servizio che il server deve eseguire,


sarà simulato, per semplicità, inserendo delle attese casuali (Thread.sleep()),

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 49
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 50
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 51
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 52
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 53
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 54
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 55
IL COSTRUTTORE THREAD POOL EXECUTOR
import java.util.concurrent.*;
public class ThreadPoolExecutor implements ExecutorService
{public ThreadPoolExecutor
(int CorePoolSize,
int MaximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue <Runnable> workqueue)......}

• il costruttore più generale: consente di personalizzare la politica di gestione


del pool
• CorePoolSize, MaximumPoolSize, keepAliveTime controllano la
gestione dei thread del pool
• workqueue è una struttura dati necessaria per memorizzare gli eventuali
tasks in attesa di esecuzione

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 56
THREAD POOL EXECUTOR
• CorePoolSize: dimensione minima del pool, definisce il core del pool. I
thread del core possono venire creati secondo le seguente modalità:

prestartAllCoreThreads( ): al momento della creazione del pool:

“on demand”. alla sottomissione di un task, si crea un nuovo thread,
anche se qualche thread già creato del corecè inattivo.
obiettivo: riempire il pool prima possibile.

quando sono stati creati tutti i threads del core, la politica varia ( vedi
pagina successiva)

• MaxPoolSize: dimensione massima del pool.



non più di MaxpoolSize threads nel pool, anche se vi sono task da
eseguire e tutti i threads sono occupati nell'elaborazione di altri tasks.

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 57
THREAD POOL EXECUTOR

alla sottomissione di un nuovo task, se tutti i thread del core sono stati creati

se un thread del core è inattivo, il task viene assegnato ad esso

altrimenti, se la coda passata come ultimo parametro del costruttore, non è
piena, il task viene inserito nella coda

i task vengono poi prelevati dalla coda ed inviati ai thread disponibili

altrimenti (coda piena e tutti i thread del core stanno eseguendo un task) si
crea un nuovo thread attivando così k thread,
corePoolSize ≤ k ≤ MaxPoolSize

altrimenti (coda piena e sono attivi MaxPoolSize threads), il task viene
respinto

• E' possibile scegliere diversi tipi di coda (tipi derivati da BlockingQueue). Il tipo
di coda scelto influisce sullo scheduling.

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 58
ELIMINAZIONE DI THREAD INUTILI
Supponiamo che un thread termini l' esecuzione di un task, e che il pool
contenga k threads:

• Se k ≤ core: il thread si mette in attesa di nuovi tasks da eseguire. L'attesa


ė indefinita.
• Se k > core, ed il thread non appartiene al core si considera il timeout T
definito al momento della costruzione del thread pool

se nessun task viene sottomesso entro T, il thread termina la sua
esecuzione, riducendo così il numero di threads del pool
• Per definire il timeout: occorre specificare

un valore (es: 50000) e

l'unità di misura utilizzata (es: TimeUnit. MILLISECONDS)

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 59
THREAD POOL EXECUTOR: QUEUE

• SynchronousQueue:dimensione uguale a 0. Ogni nuovo task T



viene eseguito immediatamente oppure respinto.

eseguito immediatamente se esiste un thread inattivo oppure se è
possibile creare un nuovo thread (numero di threads ≤ MaxPoolSize)

• LinkedBlockingQueue: dimensione illimitata



E' sempre possibile accodare un nuovo task, nel caso in cui tutti i threads
siano attivi nell'esecuzione di altri tasks

la dimensione del pool di non può superare core

• ArrayBlockingQueue: dimensione limitata, stabilita dal programmatore

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 60
THREAD POOL EXECUTOR: ISTANZE

newFixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {

return new ThreadPoolExecutor(nThreads, nThreads, 0L,


TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

newCachedThreadPool

public static ExecutorService newCachedThreadPool() {

return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L,


TimeUnit.SECONDS, new SynchronousQueue<Runnable>());

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 61
EXECUTOR LIFECYCLE

• la JVM termina la sua esecuzione quando tutti i thread (non demoni)


terminano la loro esecuzione

• è necessario analizzare il concetto di terminazione, nel caso si utilizzi un


Executor Service poichè

i tasks vengono eseguito in modo asincrono rispetto alla loro
sottomissione.

in un certo istante, alcuni task sottomessi precedentemente possono
essere completati, alcuni in esecuzione, alcuni in coda.

un thread del pool può rimanere attivo anche quando ha terminato
l'esecuzione di un task

• poichè alcuni threads possono essere sempre attivi, JAVA mette a


disposizione dell'utente alcuni metodi che permettono di terminare
l'esecuzione del pool

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 62
EXECUTORS: TERMINAZIONE
• La terminazione del pool può avvenire

in modo graduale: “finisci ciò che hai iniziato, ma non iniziare nuovi tasks”.

in modo istantaneo. “stacca la spina immediatamente”

• shutdown( ) graceful termination.



nessun task viene accettato dopo che la shutdown( ) è stata invocata.

tutti i tasks sottomessi in precedenza e non ancora terminati vengono
eseguiti, compresi quelli la cui esecuzione non è ancora iniziata (quelli
accodati).

successivamente tutti i threads del pool terminano la loro esecuzione

• shutdowNow( ) immediate termination



non accetta ulteriori tasks, ed elimina i tasks non ancora iniziati

restituisce una lista dei tasks che sono stati eliminati dalla coda

tenta di terminare l'esecuzione dei thread che stanno eseguendo i tasks
(come?)

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 63
EXECUTORS: TERMINAZIONE

ShutdownNow( )

• implementazion best effort


• non garantisce la terminazione immediata dei threads del pool
• implementazione generalmente utilizzata: invio di una interruzione ai thread
in esecuzione nel pool
• se un thread non risponde all'interruzione non termina
• infatti, se sottometto il seguente task al pool
public class ThreadLoop implements Runnable {
public ThreadLoop(){};
public void run( ){while (true) { } } }
e poi invoco la shutdownNow( ) ed osservate che il programma non
termina

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 64
EXECUTORS: TERMINAZIONE

• Life-cycle di un pool (execution service)



running

shutting down

terminated

• Un pool viene creato nello stato running, quando viene invocata una
ShutDown() o una ShutDownNow() passa allo stato shutting down, quando
tutti i thread sono terminati passa nello stato terminated

• I task sottomessi per l'esecuzione ad un pool in stato Shutting Down o


Terminated possono essere gestiti da un rejected execution handler che

può semplicemente scartarli

può sollevare una eccezione

può adottare politiche più complesse (lo vedremo in seguito)

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 65
EXECUTORS: TERMINAZIONE

Alcuni metodi definiti dalla interfaccia ExecutorService per gestire la


terminazione del pool

• void shutdown()
• List<Runnable> shutdownNow()
restituisce la lista di threads eliminati dalla coda
• boolean isShutdown()
• boolean isTerminated()
• boolean awaitTermination(long timeout, TimeUnit unit)
attende che il pool passi in stato Terminated
Per capire se l'esecuizione del pool è terminata:
• attesa passiva: invoco la awaitTermination( )
• attesa attiva: invoco ripetutatmente la isTerminated ( )

U Università degli Studi di Pisa


Dipartimento di Informatica
JAVA Threads:
Introduzione, Thread Pooling
Laura Ricci 66
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 67
ASSIGNMENT 2: SIMULAZIONE UFFICIO POSTALE

• 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 68
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 nella sala d'attesa è gestita esplicitamente
dal programma

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 69

Potrebbero piacerti anche