lezione n.11 lpr – informatica applicata approfondimenti ...ricci/22-05-12-rmi-miscellanea.pdfrmi,...
Post on 13-May-2020
6 Views
Preview:
TRANSCRIPT
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 1
Università degli Studi di Pisa Dipartimento di Informatica
Lezione n.11LPR – Informatica Applicata
Approfondimenti suRMI e Threads
22/05/2012Laura Ricci
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 2
RMI: IMPLEMENTAZIONE
• Analizziamo le caratteristiche di un servizio remoto– non vogliamo analizzare dettagliatamente l'implementazione– studiamo il comportamento tramite un insieme di esempi
• Vogliamo capire:
– poiché esiste un solo oggetto remoto, i metodi di quell'oggetto possono essere invocati in modo concorrente da client diversi o da thread diversi dello stesso client?
– In caso affermativo, viene creato un thread per ogni richiesta? Per ogni client?
– cosa accade se non sincronizzo opportunamente gli accessi sull'oggetto remoto?
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 3
RMI: INVOCAZIONE CONCORRENTE DI METODI
Per verificare se i metodi dell'oggetto remoto sono invocati in modo concorrente, • definiamo un oggetto remoto che esporta due metodi• ogni metodo non fa altro che stampare per un certo numero di volte che
è in esecuzione• attiviamo due client: uno invoca il primo metodo, uno il secondo
– si ottiene un interleaving delle stampe ! public interface threads extends java.rmi.Remote { public void MethodOne() throws java.rmi.RemoteException;
public void MethodTwo() throws java.rmi.RemoteException;
}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 4
RMI: INVOCAZIONE CONCORRENTE DI METODI
import java.rmi.*;public class threadsimpl implements threads { public threadsimpl() throws RemoteException {super();} public void MethodOne() throws RemoteException { long TimeOne = System.currentTimeMillis(); for(int index=0;index<25;index++) { System.out.println("Method ONE executing"); // Inserito un ritardo di circa mezzo secondo do{ }while ((TimeOne+500)>System.currentTimeMillis()); TimeOne = System.currentTimeMillis(); } }
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 5
RMI: INVOCAZIONE CONCORRENTE DI METODI
public void MethodTwo() throws RemoteException { long TimeTwo = System.currentTimeMillis(); for(int index=0;index<25;index++) { System.out.println("Method TWO executing"); // Inserito un ritardo di circa mezzo secondo do{ }while ((TimeTwo+500)>System.currentTimeMillis()); TimeTwo = System.currentTimeMillis(); } } }
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 6
RMI: INVOCAZIONE CONCORRENTE DI METODI
import …...public class threadserver { public threadserver() { try {LocateRegistry.createRegistry(args[0]); Registry r=LocateRegistry.getRegistry(args[0]); System.out.println("Registro Reperito"); threadsimpl c = new threadsimpl(); threads stub =(threads) UnicastRemoteObject.exportObject(c, 0); r.rebind("Threads", stub); } catch (Exception e) { System.out.println("Server Error: " + e); } } public static void main(String args[]) { new threadserver(); }}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 7
RMI: INVOCAZIONE CONCORRENTE DI METODI
public class threadsclient { public static void main(String[] args) { try { Registry r= LocateRegistry.getRegistry(args[0]); threads c = (threads) r.lookup("Threads"); if (args[1].equals("one")) c.MethodOne(); else if (args[1].equals("two")) c.MethodTwo(); else System.out.println("Error: correct usage - treadsclient port {one|two}");
} catch (Exception e){ }}}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 8
RMI: INVOCAZIONE CONCORRENTE DI METODI
Una possibile traccia di esecuzione
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 9
RMI: INVOCAZIONE CONCORRENTE DI METODI
Dalla documentazione ufficiale“A method dispatched by the RMI runtime to a remote object implementation (a server) may or may not execute in a separate thread. Calls originating from different clients Virtual Machines will execute in different threads. From the same client machine it is not guaranteed that each method will run in a separate thread”
• Invocazioni di metodi remoti provenienti da client diversi sono eseguite da diversi thread– consente di non bloccare un client in attesa della terminazione
dell'esecuzione di un metodo invocato da un altro client – ottimizza la performance del servizio remoto
• Invocazioni concorrenti provenienti dallo stesso client possono essere eseguite dallo stesso thread o da thread diversi
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 10
RMI: INVOCAZIONE CONCORRENTE DI METODI
• Supporto RMI utilizza multithreading
• Può comportare comportamenti non thread-safe
• Due client diversi possono aggiornare concorrentemente una struttura dati condivisa, producendo risultati errati– perdita di aggiornamenti
• occorre assicurare il corretto accesso alla struttura dati condivisa
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 11
CONDIVISIONE OGGETTO REMOTO
import java.rmi.Remote;import java.rmi.RemoteException;
public interface Fib extends Remote {
int getNextFib() throws RemoteException;
}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 12
CONDIVISIONE OGGETTO REMOTO
import java.rmi.*; import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry; import java.rmi.server.*;
public class FibServer implements Fib { private int F1; private int F2; public FibServer() throws RemoteException { F1 = 1; F2 = 2; } public int getNextFib() throws RemoteException { int temp = F1; F1 = F2; F2 = temp + F2; return temp;}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 13
CONDIVISIONE OGGETTO REMOTO
public static void main (String args[]) { try{LocateRegistry.createRegistry(args[0]); System.out.println("Registro Creato"); Registry r=LocateRegistry.getRegistry(args[0]); System.out.println("Registro Reperito"); FibServer statsServer = new FibServer(); Fib stub =(Fib) UnicastRemoteObject.exportObject(statsServer,0); r.rebind("FIB-SERVER", stub); } catch (RemoteException e) { System.out.println("Communication error " + e.toString());}}}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 14
CONDIVISIONE OGGETTO REMOTO
import java.rmi.*;import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry; import java.lang.*;public class FibClient {public static void main (String args[]) { Fib serverObject; Remote RemoteObject; try { Registry r= LocateRegistry.getRegistry(args[0]); RemoteObject = r.lookup("FIB-SERVER"); serverObject = (Fib)RemoteObject; for (int i = 0; i < 10; i++ System.out.println(serverObject.getNextFib()+"\n");} } catch (Exception e) { e.printStackTrace();}}}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 15
CONDIVISIONE OGGETTO REMOTO
Client1: risultati restituiti1, 2, 3, 5, 8, 13, 21, 34, 55, 89
Client2: risultati restituiti144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946
L'esecuzione di Client2 è iniziata dopo che Client1 è terminato, ma il riferimento all'oggetto remoto è rimasto lo stesso.
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 16
CONDIVISIONE OGGETTO REMOTO
• Il server genera una unca sequenza di numeri di Fibonacci, che viene 'condivisa' dai due client che accedono concorrentemente
• E' stato creato un unico oggetto remoto
• Il supporto può attivare più threads, uno per ogni client, ma ognuno di questi fa riferimento allo stesso oggetto remoto
• Comportamento non corretto per la semantica del servizio
• In generale problemi di sincronizzazione a strutture dati comuni
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 17
POLLING SERVER: ESERCIZIO 2/5/2012
import java.net.*; import java.io.*; import java.util.*;public class SocketPolling{ public static void main(String[] args) throws Exception { LinkedList ll= new LinkedList(); SocketConsumer sc = new SocketConsumer(ll); ServerSocket ss = new ServerSocket(args[0]); sc.start(); while(true) { Socket socket = ss.accept(); System.out.println("connessione accettata"); synchronized(ll) { ll.add(new SocketBucket(socket)); ll.notify();}}}}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 18
POLLING SERVER
import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;public class SocketBucket { public Socket socket; public ObjectOutputStream out; public ObjectInputStream in; public SocketBucket(Socket socket) throws IOException { this.socket = socket; out = new ObjectOutputStream(socket.getOutputStream()); in = new ObjectInputStream(socket.getInputStream()); socket.setSoTimeout(1); } }
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 19
POLLING SERVER
import......;
public class SocketConsumer extends Thread {
Vector sockets = new Vector(); LinkedList newSockets; public SocketConsumer(LinkedList newSockets) { super("ServerThread"); this.newSockets=newSockets; }
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 20
POLLING SERVER
public void run() { long dreamTime = 10; boolean foundSomething=false; System.out.println("thread attivato"); while(true) { if (this.newSockets!=null) synchronized(newSockets) { sockets.addAll(newSockets); newSockets.clear(); }
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 21
POLLING SERVER
if (sockets!=null) { Iterator it = sockets.iterator(); while(it.hasNext()) { SocketBucket bucket = (SocketBucket)it.next(); try { bucket.in.readObject(); foundSomething = true; bucket.out.writeObject(new String("Client servito")); System.out.println("ClientServito"); bucket.out.flush(); bucket.out.reset(); } catch(Exception ex) {} }}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 22
POLLING SERVER
if (foundSomething) { dreamTime = 6; } else { if (dreamTime < 1000) dreamTime *= 1.5; else dreamTime = 1000; synchronized(newSockets) { try{ newSockets.wait(dreamTime); } catch(Exception e){} }}}}}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 23
IL PROBLEMA DEI 5 FILOSOFI
cinque filosofi siedono ad una tavola rotonda con un piatto di spaghetti davanti, una forchetta (o bacchette cinesi, a seconda della versione)a destra e una forchetta a sinistra
la vita di un filosofo alterna periodi in cui mangia a quelli in cui pensa
ciascun filosofo ha bisogno di due forchette per mangiare, ma che le forchette vengano prese una per volta. Dopo essere riuscito a prendere due forchette il filosofo mangia per un pò, poi lascia le forchette e ricomincia a pensare
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 24
IL PROBLEMA DEI 5 FILOSOFI
Problema proposto da E.Dijkstra nel '65: sviluppo di un algoritmo che impedisca lo stallo (deadlock) o la morte d'inedia (starvation).
Il deadlock può verificarsi se ciascuno dei filosofi tiene in mano una forchetta senza mai riuscire a prendere l'altra. Il filosofo F1 aspetta di prendere la forchetta che ha in mano il filosofo F2, che aspetta la forchetta che ha in mano il filosofo F3, e così via in un circolo vizioso.
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 25
IL PROBLEMA DEI 5 FILOSOFI
problema proposto da E.Dijkstra nel '65 come problema di sincronizzazione tra più attività concorrenti
Starvation si verifica quando un processo non riesce mai ad acquisire le risorse di cui ha bisogno
la situazione di starvation può verificarsi indipendentemente dal deadlock se uno dei filosofi non riesce mai a prendere entrambe le forchette.
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 26
IL PROBLEMA DEI 5 FILOSOFI
public class Philosopher implements Runnable { private final Object left; private final Object right; public Philosopher(Object left, Object right) {this.left = left; this.right = right;}
private void ponder() throws InterruptedException { Thread.sleep(((int) Math.random() * 10) + 10);} public void run() { try { while (true) { synchronized (left) { synchronized (right) { ponder(); // eating } } } } catch (InterruptedException e) { return; } } }
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 27
IL PROBLEMA DEI 5 FILOSOFI
import java.util.Collection;public class Dinner { public static void main(String[] args) throws Exception { final Philosopher[] philosophers = new Philosopher[5]; Object[] chopsticks = new Object[philosophers.length]; for (int i = 0; i < chopsticks.length; i++) { chopsticks[i] = new Object(); } for (int i = 0; i < philosophers.length; i++) { Object left = chopsticks[i]; Object right =chopsticks[(i + 1) % chopsticks.length]; philosophers[i] = new Philosopher(left, right); Thread t = new Thread(philosophers[i], "Phil "+(i + 1)); t.start();}}}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 28
IL PROBLEMA DI 5 FILOSOFI
• Si può facilmente verificare che il programma può andare in deadlock
• Tutti i filosofi raccolgono la bacchetta di sinistra, poi tentano di raccogliere quella di destra, che però è già stata raccolta dal filosofo vicino
• Bacchette modellate come oggetti generici – interessa solo utilizzare la lock associata all'oggetto bacchetta– synchronized (left/right) applicata all' oggetto left/right
• acquisisce la lock sull'oggetto• rilascia la lock su quell'oggetto solo quando il blocco di codice che
segue (quello tra parentesi dopo la parola chiave synchronized termina)
• tutti i filosofi acquisiscono la lock sull'oggetto left, poi tentano di acquisire la lock sull'oggetto right
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 29
ESERCIZIO
• Scrivere una versione dei 5 filosofi in cui non si possa verificare il
deadlock
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 30
THREAD MONITORING
• per verificare automaticamente la presenza del deadlock, utilizzare l'interfaccia ThreadMXBean che consente di monitorare la esecuzione dei thread– contention monitoring: informazioni circa il tempo trascorso da un
thread in stato di bloccato e in attesa di una notifica– thread CPU time: utilizzo della CPU da parte di un thread in user mode– synchronization information e deadlock detection
• individuazione della presenza di deadlock• locks possedute dal thread e lock su cui il thread è in attesa
• implementazione della interfaccia: MXBean– per ottenere un oggetto di tipo MXBean MXBeanManagementFactory.getThreadMXBean()
• diversi metodi utilizzano l'identificatore di un thread o un vettore contenente un insieme di identificatori – identificatori di thread di tipo long
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 31
IL PROBLEMA DEI 5 FILOSOFI
import java.lang.management.*; import java.util.*;public class DeadlockChecker { private final static ThreadMXBean tmb = ManagementFactory.getThreadMXBean();public Collection<ThreadInfo> check() { Map<Long, ThreadInfo> map = new HashMap<Long,ThreadInfo>(); storeDeadlockInfo(map, tmb.findMonitorDeadlockedThreads()); storeDeadlockInfo(map, tmb.findDeadlockedThreads()); return map.values(); }private void storeDeadlockInfo(Map<Long, ThreadInfo> result, long[] ids) { if (ids != null && ids.length > 0) { for (long id:ids) {result.put(id,tmb.getThreadInfo(id));}}}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 32
IL PROBLEMA DEI 5 FILOSOFI
public class Dinner {// tutto il codice precedente della classe Dinner…......DeadlockChecker checker = new DeadlockChecker(); while (true) { Collection<ThreadInfo> threads = checker.check(); if (!threads.isEmpty()) { System.out.println("Found deadlock:"); for (ThreadInfo thread : threads) System.out.println("\t" +thread.getThreadName() System.exit(1); } } Thread.sleep(1000); }
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 33
IL PROBLEMA DEI 5 FILOSOFI
OUTPUT PRODOTTO DALLA ESECUZIONE DEL PROGRAMMA:
Found deadlock:Phil 1Phil 2Phil 3Phil 4Phil 5
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 34
THREAD/THREADPOOL PERFORMANCE
• Abbiamo più volte detto che l'utilizzo dei threadpool introduce il riuso dello stesso thread per più task e consente quindi di ridurre l'overhead introdotto dalla attivazione dei thread
• Il prossimo programma mostra:– come controllare il numero dei threads attivi contemporaneamente in
un programma
– confronta le prestazioni nel caso di un thread per task /riuso dei therads
• Utilizza oggetti di tipo Semaphore
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 35
THREAD/THREADPOOL PERFORMANCE
Semaphore: implementa un semaforo a contatore.• semaforo che include un insieme di c tokens• al momento della inizializzazione del semaforo, il valore del semaforo viene
posto a c (tutti i token disponibili)• Operazioni:
– acquire( ): blocca il thread se non è disponibile un token, altrimenti diminuisce di 1 il numero di tokens
– acquire (int count): blocca il thread se non sono disponibili count token, altrimenti diminuisce di count il numero di token
– release( ): aumenta di uno il numero di token, sblocca eventuali thread in attesa
– release (int count): aumenta di count il numero di token, sblocca eventuali threda in attesa
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 36
THREAD/THREADPOOL PERFORMANCE
import java.util.concurrent.*;
public class ThreadConstructTest { private static final int NUMBER_OF_THREADS = 100 *1000; private Semaphore semaphore = new Semaphore(10); private final Runnable job = new Runnable() { public void run() { // wait for (int i=0; i<1000; i++) { } semaphore.release(); } };
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 37
THREAD/THREADPOOL PERFORMANCE
public void noThreadPool() throws InterruptedException { for (int i = 0; i < NUMBER_OF_THREADS; i++) { semaphore.acquire(); new Thread(job).start(); } // wait for all jobs to finish semaphore.acquire(10); semaphore.release(10); }
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 38
THREAD/THREADPOOL PERFORMANCE
public void fixedThreadPool() throws InterruptedException { ExecutorService pool = Executors.newFixedThreadPool(12); for (int i = 0; i < NUMBER_OF_THREADS; i++) { semaphore.acquire(); pool.submit(job); } semaphore.acquire(10); semaphore.release(10); pool.shutdown(); }
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 39
THREAD/THREADPOOL PERFORMANCE
public static void main(String[] args) throws Exception { ThreadConstructTest test = new ThreadConstructTest();
long time = System.currentTimeMillis(); test.noThreadPool(); System.out.println("No-Thread-Pool "+ (System.currentTimeMillis() - time)); time = System.currentTimeMillis(); test.fixedThreadPool(); System.out.println("Fixed-Thread-Pool "+ (System.currentTimeMillis() - time)); }}
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 40
THREAD/THREADPOOL PERFORMANCE
OUTPUT PRODOTTO DALLA ESECUZIONE DEL PROGRAMMA:
No-Thread-Pool 11600Fixed-Thread-Pool 311
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 41
ANCORA SULLA SERIALIZZAZIONE...
• JAVA offre una ampia scelta di strutture dati• dal punto di vista del programmatore, strutture dati diverse offrono
funzionalità simile, ma....è necessario capire come vengono implementate• ad esempio la serializzazione di strutture diverse può generare un
numero di bytes molto diverso...• esempio: Vector, ArrayList, LinkedList
– offrono funzionalità simili, ma sono implementate in modo diverso...– ArrayList: un puntatore ad un solo oggetto che cresce di dimensione
(il 50 % in più) mano a mano che si inseriscono elementi. Accesso diretto
– LinkedList: un puntatore all'inizio, uno alla fine e, per ogni elemento, un puntatore all'elemento successivo ed al precedente. Accesso sequenziale.
• Come si comportano se serializzati?
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 42
ANCORA SULLA SERIALIZZAZIONE...
import java.util.*; import java.io.*;public class WritingSize {public static void test(List<String> list) throws IOException { insertJunk(list); for (int i = 0; i < 10; i++) list.add("hello world"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(baos); out.writeObject(list); out.close(); System.out.println(list.getClass().getSimpleName() + " used " + baos.toByteArray().length + " bytes"); }
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 43
ANCORA SULLA SERIALIZZAZIONE...
private static void insertJunk(List<String> list) { for(int i = 0; i<1000 * 1000; i++) list.add("junk"); list.clear(); } public static void main(String[] args) throws IOException { test(new LinkedList<String>()); test(new ArrayList<String>()); test(new Vector<String>()); } }
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 44
ANCORA SULLA SERIALIZZAZIONE...
OUTPUT PRODOTTO DALLA ESECUZIONE DEL PROGRAMMA:
LinkedList used 107 bytesArrayList used 117 bytesVector used 1310926 bytes
ArrayList 10 bytes in più per memorizzare la dimensione
Vector la clear non ha ridimensionato il vettore
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 45
THREAD POOL: POLITICHE DI SATURAZIONE
• Politica di saturazione:– richiesta nel caso si utilizzino thread pool con code di dimensione
limitata– indica le azioni che devono essere effettuate nel caso in cui il pool è
saturo, cioè la coda è piena ed i threads del pool sono tutti attivi• Strategia di default: abort il task viene rifiutato e viene sollevata una
RejectedExecutionException • E' possibile definire una politica 'ad hoc' mediante un
Rejected Execution Handler• JAVA mette a disposizione diversi Rejected Execution Handler, ognuno
dei quali implementa una diversa politica di saturazione• Selezione della politica: setRejectedExecutionHandler
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 46
THREAD POOL: POLITICHE DI SATURAZIONE
Politiche di saturazione: quando viene sottomesso un task T e la coda è piena,
possono essere adottate le seguenti politiche
• abort T viene scartato il task e viene sollevata un'eccezione
• discard rifiuta T, ma non solleva alcun tipo di eccezione
• discard oldest scarta il primo task della coda (quello che avrebbe dovuto essere eseguito successivamente) e inserisce T in coda
• caller-runs – non scarta il task e non solleva eccezioni. – cerca di rallentare (throttling, to throttle = strozzare) il flusso dei
tasks restituendo alcuni task al chiamante per l'esecuzione. – Il task non viene eseguito in un thread del pool, ma nel thread che ha
invocato la execute
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 47
THREAD POOL: POLITICHE DI SATURAZIONE
import java.util.concurrent.*;public class prova{public static void main (String args[ ]){ThreadPoolExecutor executor=new
ThreadPoolExecutor(10,11,0L,TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(100));
executor.setRejectedExecutionHandler (new ThreadPoolExecutor.CallerRunsPolicy()); } }
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 48
THREAD POOL: POLITICHE DI SATURAZIONE
• Consideriamo un Web Server – riceve richieste di servizio da parte dei clients– ogni richiesta corrisponde ad un diverso task
• Supponiamo che il Web Server definisca un thread pool che utilizzi una coda a dimensione limitata ed una politica di saturazione caller-runs.
• Se tutti i threads sono occupati e la coda è piena, il task successivo (la successiva richiesta di servizio) viene eseguita nel thread che ha invocato la execute (il main thread del server)
• Poiché l'esecuzione del servizio richiesto richiederà un intervallo di tempo ∆T, il main thread non sottometterà ulteriori taks per l'esecuzione al pool, durante ∆T
• Alcuni thread del pool possono terminare l'esecuzione del task assegnato durante ∆T, rendendosi disponibili a nuove sottomissioni
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 49
THREAD POOL: POLITICHE DI SATURAZIONE
• Inoltre, il main thread, impiegato nell'esecuzione del task rifiutato dal pool, non accetta ulteriori connessioni (non esegue l'accept sul ServerSocket) durante l'intervallo di tempo ∆T
• Le richieste di servizio vengono quindi accodate a livello TCP
• Se l'overload persiste, sarà il livello TCP che eventualmente inizierà a scartare richieste, quando la sua coda sarà, a sua volta, satura
• Conclusione: se il server è sovraccarico, si può implementare una graceful degradation, spostando gradualmente il sovraccarico– dai thread del pool alla coda associata al pool, – dalla coda alla applicazione, – dall'applicazione al livello TCP – Il livello TCP è in grado di bloccare il client, mediante il meccanismo di
controllo del flusso
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 50
POLITICHE DI SATURAZIONE: ESEMPI
public void process( ){ ThreadPoolExecutor exec = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue(0)); exec.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); while(true) {Object work = acquireWork(); if(work != null) exec.execute(new WorkerThread(work)); }}• supponiamo che 6 nuovi tasks vengano sottomessi a process, i primi 5 vengono
distribuiti ai worker threads, il sesto viene rifiutato ed eseguito da process• se tutti i tasks richiedono approssimativamente lo stesso tempo, tutti i
threads terminano l'esecuzione dei tasks approssimativamente nello stesso tempo
• se il sesto tasks richiede più tempo, il thread del pool rimangono inattivi
Dipartimento di InformaticaUniversità degli Studi di Pisa
RMI, ThreadsApprofondimenti
Laura Ricci 51
POLITICHE DI SATURAZIONE: ESEMPI
public void process(){ ThreadPoolExecutor exec = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(5)); exec.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); while(true) {Object work = acquireWork(); if(work != null) {exec.execute(new WorkerThread(work)); }}}• Quando un task viene rifiutato, esistono alcuni task in coda
• Anche se process impiega molto tempo nella esecuzione del task rifiutato, esiste del lavoro extra che il therad pool distribuisce ai workers, mentre process elabora il task rifiutato
top related