Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
263
1. Devo implementarla ogni volta che un task (ovvero un oggetto) deve essere eseguito da un thread 2. Cos facendo possi estendere altre classi
264
265
public void run() { for (int i = 0; i < 10; i++) { cubbyhole.put(i); System.out.println("Producer #" + this.number + " put: " + i); try { sleep((int)(Math.random() * 100)); } catch (InterruptedException e) { } } } }
Mai usare costanti in questo modo. Meglio definire delle variabili di istanza, piuttosto
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
266
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
267
Se la risorsa non viene condivisa in modo sincronizzato, si possono avere problemi di consistenza
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
268
269
Esercizio 24
Si modifichi il codice desempio del problema produttore/ consumatore in modo tale da considerare una capacit massima del ripostiglio pari a size, propriet del ripostiglio. Si testi successivamente il sistema con un produttore e diversi consumatori. Per chi volesse, potrebbe contare il numero di volte che un oggetto viene messo nel (preso dal) ripostiglio, per poi stampare allutente una statistica di utilizzo.
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
270
Due alternative
o il richiedente si pone in attesa sul metodo acquire() o fino a che una risorsa non viene rilasciata da un altro client (con il metodo release())
avete a disposizione altri interessanti metodi, come il tryAcquire() dove il richiedente si pone in attesa per un limite di tempo e poi esce (senza acquisire la risorsa)
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
271
Es. Party
Esempio. La risorsa condivisa una festa (con un numero di posti liberi limitato) e un numero di invitati maggiore. Alcuni invitati, per pigrizia, attendono l'ingresso ma non oltre un certo tempo, dopodich lasciano perdere e si allontanano.
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
272
Es. Party
public class Party { //Dimensione massima della sala: quante persone al massimo riusciamo a servire int dimensione; //Il semaforo che controller gli accessi Semaphore semaphore; public Party(int dim){ this.dimensione = dim; //creiamo il semaforo con il numero massimo di accessi this.semaphore = new Semaphore(dimensione); } public boolean goIn(){ try{ semaphore.acquire(); if (semaphore.availablePermits()==0) System.out.println("Please wait... nessun posto disponibile!"); return true; }catch(InterruptedException e){ e.printStackTrace(); } return false; } public boolean goIn(long time){ try{ boolean in = semaphore.tryAcquire(time, TimeUnit.SECONDS); if (semaphore.availablePermits()==0) System.out.println("Please wait... nessun posto disponibile!"); return in; }catch(InterruptedException e){ e.printStackTrace(); } return false; } public void goOut(){ semaphore.release(); System.out.println("Uno meno! Posti liberi... "+semaphore.availablePermits()); 273 }
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
Es. Party
public class Invited extends Thread { String name; Party party; public Invited(String name, Party party){ this.name = name; this.party = party; } //Facciamo un ciclo infinito di ingressi, attese, uscite, attese, ... public void run(){ while(true){ System.out.println("["+name+": ] Sono in coda. Aspetto."); party.goIn(); System.out.println("["+name+": ] Yuppy! Sono dentro."); try{ //Si diverte un po' alla festa int timeToSleep = (int) (Math.random()*10); System.out.println("["+name+": ] rimarr "+timeToSleep+" secs."); TimeUnit.SECONDS.sleep(timeToSleep); }catch(InterruptedException e){ e.printStackTrace(); } //decide di uscire... party.goOut(); System.out.println("["+name+": ] Esco a prendere aria."); try{ //sta un po' fuori... int timeToSleep = (int) (Math.random()*10); TimeUnit.SECONDS.sleep(timeToSleep); }catch(InterruptedException e){ e.printStackTrace(); } } } 274
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
Es. Party
public class LazyInvited extends Invited { public LazyInvited(String name, Party party) { super(name, party); } //Facciamo un ciclo infinito di ingressi (con attesa limitata), attese, uscite, attese public void run(){ while(true){ System.out.println("["+name+": ] Sono in coda. Aspetter un po' (5 sec)."); boolean in = party.goIn(5); if (in){ System.out.println("["+name+": ] Yuppy! Sono dentro."); try{ //Si diverte un po' alla festa int timeToSleep = (int) (Math.random()*10); System.out.println("["+name+": ] rimarr "+timeToSleep+ secs."); TimeUnit.SECONDS.sleep(timeToSleep); }catch(InterruptedException e){ e.printStackTrace(); } //decide di uscire... party.goOut(); System.out.println("["+name+": ] Esco a prendere aria."); }else{ //timeout di attesa scaduto! System.out.println("["+name+": ] Basta! mi sono rotto, esco."); } try{ //sta un po' fuori... int timeToSleep = (int) (Math.random()*10); TimeUnit.SECONDS.sleep(timeToSleep); }catch(InterruptedException e){ e.printStackTrace(); } 275
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
Es. Party
public class MainPR { //Simulazione del PR che invita la gente al party public static void main(String[] args) { //Definiamo il party di 20 persone concorrenti Party party = new Party(20); //creiamo 40 invitati Invited inLista[] = new Invited[40]; //met saranno lazy, gli altri no for(int i=0;i<inLista.length;i++){ Invited tmp; if (i%2==0) tmp = new Invited("NotLazy#"+i, party); else tmp = new LazyInvited("Lazy#"+i, party); } inLista[i]=tmp;
CopyOnWriteArraySet<E>
Garantiscono laccesso sincronizzato alle risorse condivise senza che lutente si debba preoccupare della consistenza
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
277
Le code in Java non implementano lattesa possibile sincronizzarle usando semafori o monitor oppure usando linterfaccia BlockingQueue e le sue implementazioni
o o o o o
o i metodi take() e put() (rimozione ed inserimento) sono bloccanti per il thread che li invoca
comportamento di coda con attesa ancora una volta non dovete preoccuparvi di nulla
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
278
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
279
280
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
10
Permette alle implementazioni di Java di usare istruzioni atomiche efficienti a basso livello che sono disponibili sui processori moderni
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
282
283
11
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
284
285
12
E come complicarsela
o Problema
o la logica di business accoppiata con la logica di esecuzione (ciclo di vita) dello stesso Thread o Come disaccoppiare le due cose?
i metodi statici di java.util.concurrent.Executors ci consentono l'accesso a degli Executor standard, che sono:
o o o o Single Thread Executor Fixed Thread Executor Cached Thread Executor Scheduled Thread Executor
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
E come complicarsela
package it.html.threads; public class EchoServer { public static void main(String[] args) { ServerSocket server = null; //Avviamo il server try { server = new ServerSocket(6666); } catch (IOException e) { System.out.println("Eccezione all'avvio del server: "+e.getMessage()); System.exit(-1); } //Creo un pool di thread concorrenti ExecutorService executor = Executors.newFixedThreadPool(5); //Aspettiamo una nuova connessione cui deleghiamo l'esecuzione //all'executor service definito in precedenza while(true){ try{ System.out.println("Waiting incoming connection..."); Socket incoming = server.accept(); executor.execute(new EchoThread(incoming)); }catch(Exception e){ executor.shutdown(); } }
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
287
13
E come complicarsela
class EchoThread implements Runnable{ Socket socket; public EchoThread(Socket socket){ this.socket = socket; } public void run(){ System.out.println("Incoming connection: "+socket.getInetAddress()); //Continua con la lettura/scrittura sulla socket aperta... } }
Nota: Anzich effettuare l'esecuzione (con il classico metodo start()) qui deleghiamo l'esecuzione all'executor service, ignorando come questo gestisca la logica di avvio
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
288
Callable
o
o non pu essere modificato per poter essere gestito dallo scheduler della JVM o in soldoni, non avremo mai la possibilit di avere un thread che
ci restituisca un risultato con un'interrogazione diretta che sia in grado di sollevare checked exceptions
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
289
14
Callable
immaginiamo di avere un task che restituisca il risultato di una ricerca su un catalogo di prodotti
public class CallableTask implements Callable<Collection<String>> { String keyword; public CallableTask(String key){ this.keyword = key; } @Override public Collection<String> call() throws EmptyListException{ Collection<String> toRet = new Vector<String>(); //... simuliamo la presenza di oggetti in un db toRet.add("Product #CADASD432"); toRet.add("Product #CADAS322"); //... se non ci sono oggetti solleviamo un'eccezione if (toRet.isEmpty()) throw new EmptyListException("Nessun elemento trovato!"); //... simuliamo il tempo di ricerca try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { // NOOP } } return toRet;
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
290
Callable
public static void main(String args[]) throws InterruptedException{ CallableTask task = new CallableTask("games"); System.out.println("Search result (passano 5 secondi prima di vedere il risultato):"); try { showResult(task.call()); } catch (EmptyListException e) { System.out.println("Nessun oggetto trovato"); } System.out.println("... fine della computazione"); } class EmptyListException extends Exception{ public EmptyListException(String string) { super(string); } }
o o
In teoria
o
ci d la possibilit di avere un'esecuzione asincrona con un tipo di ritorno e una lista di eccezioni che desideriamo
In realt
o o
di asincrono c' ben poco l'esecuzione del metodo call() arresta l'esecuzione del flusso del main, in attesa del risultato Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011
S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
291
15
Future e FutureTask
o
o Future o FutureTask
Ci vengono in aiuto
o Sottomettiamo a un ExecutorService un oggetto di tipo Callable<T> (tramite il metodo submit()) o Otteniamo come risultato un oggetto Future<T> e lo utilizziamo per
l'esecuzione concorrente di un'attivit recuperarne il risultato interrogando il metodo get (che restituisce un istanza di T) sul Future
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
292
Future e FutureTask
Stessa operazione di ricerca ma in maniera parallela
public static void main(String args[]) throws InterruptedException{ //Definiamo un executor ExecutorService executor = Executors.newSingleThreadExecutor(); //Creiamo un task asincrono CallableTask task = new CallableTask("games"); //e lo wrappiamo in un oggetto future Future<Collection<String>> result = executor.submit(task); System.out.println("Search result (soliti 5 secondi):"); //...nel frattempo possiamo fare altri compiti, come preparare un layout di presentazione System.out.println("#------------- games found ---- ++"); //prendiamo il risultato, e se non stato eseguito attendiamo try { showResult(result.get()); } catch (ExecutionException e) { System.out.println("Eccezione nell'esecuzione della ricerca"); } System.out.println("... fine della computazione"); }
Nota: il metodo get(long,TimeUnit) permette di settare un timeout di attesa, oltre il quale l'attivit cancellata
utile ad esempio in contesti real-time o per attivit con deadline
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
293
16
quando una classe accede a un blocco synchronized non ha modo di uscirne finch quella sezione non liberata
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
o Ma in questo caso pu essere rilasciato da thread diversi dal proprietario (I semafori non implementano nessuna funzionalit di appartenenza)
Ma molto pi potente
cio possibile sviluppare logiche pi complesse esiste anche la classe Condition Se scade si eseguono altre azioni
o O ancora Lock che possono essere interrotti da thread diversi dallattuale proprietario
Al solito
295
17
Java.util.concurrent
o Arricchisce Java di funzionalit utili alla gestione della concorrenza
o Oltre synchronized, wait, notify o Sia semplificando la vita o Sia complicandocela
pi flessibili pi strutturati
Ma introducendo Thread
Laboratorio di sistemi e reti (Comunicazione Digitale) - A.A. 2010-2011 S. Bassis (bassis@dsi.unimi.it) Universit di Milano D.S.I.
297
18
298
19