Multithreading in Java
Un programma sequenziale (single thread) class ABC {. public void main(..) {.. begin body end 2
Un programmamultithreaded Main Thread start start start Thread A Thread B Thread C (le thread possono scambiare dati) 3
Applicazioniweb/Internet Servono molti utenti simultaneamente PC client Internet Server Local Area Network PDA 4
Server multithreaded Servono diversi Client concorrentemente Client 1 Process Server Process Internet Server Threads Client 2 Process 5
Applicazioni moderne necessitano multithreading Editing e Printing di documenti in background. Printing Thread Editing Thread 6
Copiadifile multithreaded/parallela reader() { - - - - - - - - - - lock(buff[i]); read(src,buff[i]); unlock(buff[i]); - - - - - - - - - - buff[0] buff[1] writer() { - - - - - - - - - - lock(buff[i]); write(src,buff[i]); unlock(buff[i]); - - - - - - - - - - Cooperative Parallel Synchronized Threads 7
Processo ha risorse di computazione proprie ad es. ha il proprio spazio di memoria Sinonimo di programma/applicazione in esecuzione Tuttavia, ciò che è percepito dall utente come una singola applicazione spesso è il frutto dell attività di vari processi che cooperano la maggior parte delle implementazioni della JVM girano come un singolo processo
Thread processo leggero (lightweight) sia i processi che le thread forniscono un ambiente di esecuzione (del codice) creare una nuova thread richiede meno risorse che creare un processo ogni thread esiste nell ambito di un processo (e ogni processo ha almeno una thread di esecuzione) le thread di uno stesso processo condividono le risorse del processo (comunicazione tra thread più efficiente)
Processisingle/multi-threaded single-threaded threads di esecuzione multithreaded Flusso di istruzioni singolo Spazio degli indirizzi (memoria) comune Flusso di istruzioni multiplo 10
Ancorasu thread Una thread può essere vista come un pezzo di codice in esecuzione concorrentemente con altre thread Ogni thread consiste nell esecuzione di un sequenza di istruzioni ordinate staticamente (computazione sequenziale) Le thread sono usate per esprimere la concorrenza sia su macchine con processore singolo che multiplo L attività di programmazione con thread multiple è detto multithreading o multithreaded programming 11
Threade Java il multithreading è una caratteristica essenziale di Java ogni programma Java ha una main thread da cui possono essere generate altre thread la JVM esegue anche delle thread di sistema insieme al programma utente gestione della memoria trattamento dei segnali
Thread e Java Java supporta il multithreading fornendo primitive per: creazione di thread sincronizzazione thread scheduling comunicazione tra thread il Java Garbage Collector è eseguito come una thread a bassa priorità Il concetto di thread in Java è catturato dalla classe Thread 13
Classe Thread definisce una serie di metodi per la gestione delle thread implementa l interfaccia Runnable che richiede un metodo run (firma public void run()) il metodo run rappresenta il main della thread corrispondente run della classe Thread non fa nulla per programmare una thread occorre fornire una implementazione di run esistono due modi 14
Programmazionedi una thread estensione della classethread con riscrittura di run istanziazione di Thread fornendo un oggetto Runnable 15
Estensionedellaclasse Thread public class MyThread extends Thread { public void run() { // thread body of execution istanzia una thread: MyThread thr1 = new MyThread(); avvia l esecuzione della thread: thr1.start(); 16
Esempio public class MyThread extends Thread { // la thread public void run() { System.out.println(" questa thread è in esecuzione... "); // end class MyThread public class ThreadEx1 { // un programa che istanzia MyThread public static void main(string [] args ) { MyThread t = new MyThread(); // l invocazione di start(), invocherà a sua volta run(). t.start(); // end main() // end class ThreadEx1 17
Attraverso un oggetto Runnable public class MyThread implements Runnable {... public void run() { // thread body of execution istanzia oggetto: MyThread myobject = new MyThread(); istanzia una thread che si comporta come specificato da myobject: Thread thr1 = new Thread( myobject ); avvia esecuzione: thr1.start(); 18
Esempio public class MyThread implements Runnable { public void run() { System.out.println(" questa thread è in esecuzione... "); // end class MyThread public class ThreadEx2 { public static void main(string [] args ) { Thread t = new Thread(new MyThread()); t.start(); // end main() // end class ThreadEx2 19
Esecuzioni di programmi multithreaded l ordine in cui vengono eseguite le istruzioni di ogni thread nei processori non prevedibile in assenza di sincronizzazioni sono possibili tutti gli interleaving delle esecuzioni di ciascuna thread successive esecuzioni possono dar luogo a comportamenti differenti 20
Esempio public class Conta implements Runnable{ public Conta(int x){up = x; public void run(){ threadmessage("start!"); for (int i=0; i<up;i++) threadmessage(""+(1+i)); threadmessage("finish!"); //Display a message, preceded by the name of the current thread static void threadmessage(string message) { String threadname = Thread.currentThread().getName(); System.out.println(threadName+ ": "+ message); private int up; 21
Esempio (tre threadconta) public class ContaTester { public static void main(string[] args) { Thread t1 = new Thread(new Conta(10)); Thread t2 = new Thread(new Conta(10)); Thread t3 = new Thread(new Conta(10)); t1.start(); t2.start(); t3.start(); 22
Un rundel programma Thread-1: Start! Thread-1: 1 Thread-1: 2 Thread-1: 3 Thread-1: 4 Thread-1: 5 Thread-0: Start! Thread-0: 1 Thread-0: 2 Thread-0: 3 Thread-0: 4 Thread-0: 5 Thread-0: 6 Thread-0: 7 Thread-0: 8 Thread-1: 6 Thread-2: Start! Thread-2: 1 Thread-2: 2 Thread-2: 3 Thread-2: 4 Thread-2: 5 Thread-2: 6 Thread-2: 7 Thread-2: 8 Thread-2: 9 Thread-2: 10 Thread-2: Finish! Thread-0: 9 Thread-0: 10 Thread-0: Finish! Thread-1: 7 Thread-1: 8 Thread-1: 9 Thread-1: 10 Thread-1: Finish! 23
Altri run Thread-0: Start! Thread-0: 1 Thread-0: 2 Thread-0: 3 Thread-0: 4 Thread-0: 5 Thread-0: 6 Thread-0: 7 Thread-0: 8 Thread-1: Start! Thread-1: 1 Thread-1: 2 Thread-1: 3 Thread-1: 4 Thread-1: 5 Thread-2: Start! Thread-2: 1 Thread-1: 6 Thread-1: 7 Thread-1: 8 Thread-1: 9 Thread-1: 10 Thread-1: Finish! Thread-2: 2 Thread-0: 9 Thread-0: 10 Thread-0: Finish! Thread-2: 3 Thread-2: 4 Thread-2: 5 Thread-2: 6 Thread-2: 7 Thread-2: 8 Thread-2: 9 Thread-2: 10 Thread-2: Finish! Thread-0: Start! Thread-0: 1 Thread-0: 2 Thread-0: 3 Thread-0: 4 Thread-0: 5 Thread-0: 6 Thread-0: 7 Thread-0: 8 Thread-0: 9 Thread-0: 10 Thread-1: Start! Thread-2: Start! Thread-2: 1 Thread-2: 2 Thread-2: 3 Thread-2: 4 Thread-2: 5 Thread-2: 6 Thread-2: 7 Thread-2: 8 Thread-2: 9 Thread-2: 10 Thread-2: Finish! Thread-0: Finish! Thread-1: 1 Thread-1: 2 Thread-1: 3 Thread-1: 4 Thread-1: 5 Thread-1: 6 Thread-1: 7 Thread-1: 8 Thread-1: 9 Thread-1: 10 Thread-1: Finish! Thread-0: Start! Thread-0: 1 Thread-0: 2 Thread-0: 3 Thread-0: 4 Thread-0: 5 Thread-0: 6 Thread-0: 7 Thread-0: 8 Thread-0: 9 Thread-1: Start! Thread-1: 1 Thread-1: 2 Thread-1: 3 Thread-1: 4 Thread-1: 5 Thread-1: 6 Thread-1: 7 Thread-1: 8 Thread-0: 10 Thread-1: 9 Thread-0: Finish! Thread-1: 10 Thread-1: Finish! Thread-2: Start! Thread-2: 1 Thread-2: 2 Thread-2: 3 Thread-2: 4 Thread-2: 5 Thread-2: 6 Thread-2: 7 Thread-2: 8 Thread-2: 9 Thread-2: 10 Thread-2: Finish! Thread-1: Start! Thread-1: 1 Thread-1: 2 Thread-1: 3 Thread-1: 4 Thread-0: Start! Thread-0: 1 Thread-0: 2 Thread-0: 3 Thread-0: 4 Thread-0: 5 Thread-0: 6 Thread-0: 7 Thread-0: 8 Thread-0: 9 Thread-0: 10 Thread-0: Finish! Thread-2: Start! Thread-1: 5 Thread-1: 6 Thread-1: 7 Thread-1: 8 Thread-1: 9 Thread-1: 10 Thread-1: Finish! Thread-2: 1 Thread-2: 2 Thread-2: 3 Thread-2: 4 Thread-2: 5 Thread-2: 6 Thread-2: 7 Thread-2: 8 Thread-2: 9 Thread-2: 10 Thread-2: Finish! Thread-0: Start! Thread-1: Start! Thread-1: 1 Thread-1: 2 Thread-1: 3 Thread-1: 4 Thread-1: 5 Thread-1: 6 Thread-1: 7 Thread-1: 8 Thread-1: 9 Thread-1: 10 Thread-1: Finish! Thread-2: Start! Thread-2: 1 Thread-2: 2 Thread-2: 3 Thread-2: 4 Thread-2: 5 Thread-2: 6 Thread-2: 7 Thread-2: 8 Thread-2: 9 Thread-2: 10 Thread-2: Finish! Thread-0: 1 Thread-0: 2 Thread-0: 3 Thread-0: 4 Thread-0: 5 Thread-0: 6 Thread-0: 7 Thread-0: 8 Thread-0: 9 Thread-0: 10 Thread-0: Finish! 24
Stati dell esecuzionedi una thread new start() blocked eseguibile non-eseguibile unblocked dead 25
Metodo sleep metodo static di Thread Thread.sleep(3000) causa la sospensione dell esecuzione della thread corrente per 3 secondi il periodo di pausa può essere terminato con un interrupt se un interrupt avviene mentre sleep è in esecuzione, sleep lancia l eccezione controllata InterruptedException (sottoclasse di Exception) 26
Metodi currentthreade join Thread.currentThread() restituisce il riferimento all oggetto Thread correntemente in esecuzione metodo static di Thread t.join() mette la thread in esecuzione in attesa fino a quando la thread t termina metodo non-static di Thread 27
Interrupts un interrupt può essere inviato da una thread per interrompere l attività di un altra thread athread.interrupt() invia un interrupt alla thread athread ( setta l interrupt status della thread) se l interrupt avviene mentre sono in esecuzione metodi come sleep o join, viene lanciata un eccezione altrimenti, si può testare se un interrupt è avvenuto con i metodi interrupted(): metodo static, azzera l interrupt status isinterrupted(): metodo predicativo, lascia inalterato l interrupt status 28
Esempio public class SimpleThreads { //Display a message, preceded by the name of the current thread static void threadmessage(string message) { String threadname = Thread.currentThread().getName(); System.out.println(threadName+ ": "+ message); private static class MessageLoop implements Runnable { public void run() { String importantinfo[] = { Primo", Secondo", Terzo", Quarto ; for (int i = 0; i < importantinfo.length; i++) { try {Thread.sleep(4000); //Pause for 4 seconds catch (InterruptedException e) {threadmessage("i wasn't done!"); finally { threadmessage(importantinfo[i]); //Print a message 29
Esempio public static void main(string args[]) throws InterruptedException { long patience = 1000*6; //Delay before we interrupt MessageLoop thread threadmessage("starting MessageLoop thread"); long starttime = System.currentTimeMillis(); Thread t = new Thread(new MessageLoop()); t.start(); threadmessage("waiting for MessageLoop thread to finish"); while (t.isalive()) { //loop until MessageLoop thread exits threadmessage("still waiting..."); t.join(1000); //Wait maximum of 1 second for MessageLoop thread to finish if (((System.currentTimeMillis() - starttime) > patience) && t.isalive()) { threadmessage("tired of waiting!"); t.interrupt(); t.join(); threadmessage("finally!"); 30
Esempio: output main: Starting MessageLoop thread main: Waiting for MessageLoop thread to finish main: Still waiting... main: Still waiting... main: Still waiting... main: Still waiting... Thread-0: Primo main: Still waiting... main: Still waiting... main: Tired of waiting! Thread-0: I wasn't done! Thread-0: Secondo Thread-0: Terzo Thread-0: Quarto main: Finally! 31
Priorità in Java, ogni thread ha una priorità che influenza l ordine in cui vengono schedulate le thread in esecuzione. se non viene settata diversamente le thread hanno una priorità di default (NORM_PRIORITY) e sono servite in ordine di richiesta (FIFO) la priorità di una thread t si può cambiare con il metodo setpriority(int) Valori di priorità predefinite della classe Thread: MIN_PRIORITY = 1, NORM_PRIORITY=5, MAX_PRIORITY=10 32
Comunicazione tra thread Accesso condiviso ai dati due o più thread accedono ad uno stesso oggetto Ad es. due thread che condividono un contatore due thread che richiedono di inviare l output su System.out due operazioni simultanee su uno stesso conto corrente 33
Esempio Classe che implementa un contatore con incremento, decremento e lettura valore: public class Counter { private int c = 0; public void increment() { c++; public void decrement() {if (c> 0) c--; public int value() { return c; 34
Possibili errori con dati condivisi Interferenza avviene quando due operazioni (in thread differenti) sullo stesso dato si interfogliano Ad es., thread A incrementa il counter e thread B lo decrementa (incremento e decremento di variabili richiedono più micro-istruzioni: recupera valore, esegui operazione, salva risultato) Possibile esecuzione: A legge c; B legge c; A incrementa c; B decrementa c; A salva risultato; B salva risultato. Errore: il risultato calcolato da A viene perso 35
Possibili errori con dati condivisi Inconsistenza della memoria Due thread hanno una visione differente di un dato condiviso Ad es. x è condivisa tra thread A e thread B ed è inizializzata a 0 A esegue x++ B esegue System.out.println(x) Quale valore deve assumere B per x? 0 o 1? Nessuna assunzione può essere fatta in assenza di sincronizzazione tra le attività di A e B 36
Sequenza temporale istruzioni E corretto assumere che: ogni istruzione che precede nel codice un istruzione del tipo t.start(), avviene prima di tutte le istruzioni della thread t ogni istruzione che segue nel codice un istruzione del tipo t.join(), avviene dopo tutte le istruzioni della thread t La sincronizzazione può essere usata per forzare un ordine di esecuzione tra istruzioni di thread concorrenti 37
Sincronizzazione In Java, è costruita attorno all acquisizione di monitor (o intrinsic lock o monitor lock) Ogni oggetto ha un monitor associato Una thread che necessita di un accesso esclusivo e consistente ad un membro di un oggetto acquisisce il suo monitor prima e lo rilascia quando ha terminato Fin tanto che una thread è in possesso di un monitor nessuna altra thread può acquisirlo 38
Metodi synchronized public synchronized void increment() { c++; dichiarare un metodo synchronized assicura un esecuzione atomica del metodo stesso (come se fosse un unica istruzione) l invocazione di un metodo synchronized in una thread comporta l implicita acquisizione del monitor del parametro implicito se il monitor non è disponibile allora la thread resta in attesa il monitor viene rilasciato automaticamente quando viene eseguito il return dal metodo 39
Metodi synchronized in caso di due esecuzioni concorrenti di metodi synchronized di uno stesso oggetto il codice non viene interfogliato viene eseguita prima una chiamata e poi l altra mentre una chiamata è attiva tutte le altre chiamate vengono messe in attesa synchronized non si usa con costruttori (non serve) con i metodi static comporta l acquisizione del monitor dell oggetto Class corrispondente alla classe risolve i problemi di interferenza e consistenza della memoria 40
Esempio public class Adder implements Runnable { private Counter counter; public Adder(Counter acounter) { counter = acounter; public void run() {counter.increment(); // end class Adder counter public class Stopper implements Runnable { private Counter counter; public Stopper (Counter acounter) { counter = acounter; public void run() {counter.decrement(); // end class Stopper 41
Esempio public class SharedCounterTester{ public static void main(string [] args ) { Counter counterobject = new Counter(); Thread t1 = new Thread(new Adder(counterObject)); Thread t2 = new Thread(new Stopper(counterObject)); Thread t3 = new Thread(new Stopper(counterObject)); t1.start(); t2.start(); t3.start(); try{t1.join(); t2.join(); t3.join(); catch(interruptedexception e){ System.out.println(counterObject.value()); // end main() il contatore può valere -1!!! 42
Esempio Il problema viene risolto con: public class Counter { private int c = 0; public void increment() { c++; public synchronized void decrement() { if (c>0) c--; public int value() { return c; 43
Istruzioni synchronized synchronized si può usare anche su istruzioni In questo caso bisogna specificare un oggetto su cui acquisire il monitor synchronized(this) { lastname = name; namecount++; richiede il monitor del parametro implicito blocca l esecuzione di altri metodi su questo oggetto Se ciò non è necessario, possiamo usare oggetti differenti solo per scopi di sincronizzazione 44
Oggetti usati come monitor public class MsLunch { private long c1 = 0, c2 = 0; private Object lock1 = new Object(); private Object lock2 = new Object(); public void inc1() { synchronized(lock1) { c1++; public void inc2() { synchronized(lock2) { c2++; Gli incrementi di c1 e c2 possono essere interfogliati ma non possiamo interfogliare due incrementi della stessa variabile 45
Acquisizione multipla di un monitor Una thread non può acquisire un monitor posseduto da un altra thread ma può riacquisire un monitor che già possiede Viene consentito per evitare che una thread possa bloccare se stessa un codice sincronizzato invoca un metodo che contiene altro codice sincronizzato con lo stesso monitor 46
Accesso atomic Un azione è atomic se viene percepita come un tutt uno (come un un unica istruzione elementare) viene eseguita completamente senza interruzione o non viene eseguita c++ non è atomic Accesso atomic (lettura/scrittura) garantito su variabili dichiarate volatile variabili con riferimenti a oggetti variabili di tipo primitivo esclusi long e double Usare accessi atomic è più efficiente che usare synchronized (non usa monitor) 47
Metodo wait metodo di Object obj.wait(10000) all interno del codice di una thread T causa la sospensione dell esecuzione di T finché: sono trascorsi 10 secondi o un altra thread invoca notify() su obj e T viene scelta come thread da svegliare o un altra thread invoca notifyall() su obj o un altra thread invia un interrupt su T se si usa wait() oppure wait(0) non c è timeout 48
Metodo wait per invocare wait su obj una thread deve possedere il monitor di obj il monitor viene rilasciato subito dopo che la thread sospende l esecuzione altrimenti viene sollevata una IllegalMonitorStateException (eccezione non controllata) invocare wait all interno di un metodo synchronized è un modo semplice per ottenere il monitor del parametro implicito se un interrupt avviene mentre wait è in esecuzione, wait lancia l eccezione controllata InterruptedException (sottoclasse di Exception) 49
notifyalle notify notifyall sveglia tutte le thread in attesa sull oggetto su cui è invocato notify sveglia una thread in attesa sull oggetto su cui è invocato se ci sono più thread in attesa la scelta è arbitraria e dipende dall implementazione è utile solo quando si eseguono molte thread dello stesso tipo e quindi non importa seguire un ordine per entrambi i metodi è necessario acquisire prima il monitor dell oggetto su cui vengono invocati 50
Esempio: producer-consumerpattern una thread producer (produce dati) e una thread consumer (consuma dati) le thread comunicano attraverso un oggetto condiviso Requisiti da rispettare il consumer non deve provare a prendere il dato prima che il producer lo rilasci il producer non deve rilasciare un nuovo dato prima che il consumer prenda il precedente 51
Esempio: oggetto condiviso public class Drop { private String message; //from producer to consumer private boolean empty = true; // true means no new message public synchronized String take() { //wait until message is available. while (empty) { try { wait(); catch (InterruptedException e) { empty = true; //toggle status notifyall(); //notify producer that status has changed return message; public synchronized void put(string message) { //wait until message has been retrieved while (!empty) { try { wait(); catch (InterruptedException e) { empty = false; this.message = message; notifyall(); 52
Esempio: producer import java.util.random; public class Producer implements Runnable { private Drop drop; public Producer(Drop drop) { this.drop = drop; public void run() { String importantinfo[ ] = { "Mares eat oats", "Does eat oats", "Little lambs eat ivy", "A kid will eat ivy too" ; Random random = new Random(); for (int i = 0; i < importantinfo.length; i++) { drop.put(importantinfo[i]); try { Thread.sleep(random.nextInt(5000)); catch (InterruptedException e) { drop.put("done"); 53
Esempio: Consumer import java.util.random; public class Consumer implements Runnable { private Drop drop; public Consumer(Drop drop) { this.drop = drop; public void run() { Random random = new Random(); String message; while(!(message = drop.take()).equals("done")) { System.out.println("MESSAGE: "+ message); try { Thread.sleep(random.nextInt(5000)); catch (InterruptedException e) { 54
Esempio: classe tester public class ProducerConsumerExample { public static void main(string[] args) { Drop drop = new Drop(); (new Thread(new Producer(drop))).start(); (new Thread(new Consumer(drop))).start(); 55
Osservazioni non bisogna abusare nell uso di synchronized la sincronizzazione sequenzializza il codice opposto di parallelismo la sincronizzazione può ostacolare o fin anche bloccare la computazione (liveness) thread che sono in attesa reciproca (deadlock) thread che non riescono ad accedere frequentemente a risorse (starvation) thread che tentano di sincronizzarsi senza riuscirci (livelock) 56
Sincronizzazione: problemi Deadlock due o più thread si bloccano a vicenda viene invocato un metodo synchronized su un oggetto su cui l altra thread ha in esecuzione un metodo synchronized e viceversa Starvation una thread non riesce ad accedere ad una risorsa regolarmente un metodo synchronized di un oggetto impiega molto tempo e una thread lo invoca spesso. Altre thread che richiedono accesso ad un metodo synchronized dello stesso oggetto possono essere bloccate 57
Sincronizzazione: problemi Livelock due thread che agiscono una in risposta all azione dell altra due persone che vogliono attraversare contemporaneamente una strettoia. Una si fa a destra e l altra a sinistra ma non riescono a passare. Quindi la prima si sposta ora a sinistra e la seconda in risposta si sposta a destra, e così via. 58
Oggetti immutabili e concorrenza oggetti immutabili sono molto utili nei programmi concorrenti non possono cambiare stato, quindi nessuna interferenza tra thread inconsistenza della memoria oggetti mutabili vs. oggetti immutabili cambio di valore vs. nuovo oggetto istanziare oggetti non è un operazione particolarmente onerosa costo è compensato da una più efficiente garbage collection e dall eliminazione del codice per evitare inconsistenze per gli oggetti immutabili 59
Classe SynchronizedRGB(1) public class SynchronizedRGB { private int red, green, blue; //Values must be between 0 and 255 private String name; private void check(int red, int green, int blue) { if (red < 0 red > 255 green < 0 green > 255 blue < 0 blue > 255) { throw new IllegalArgumentException(); public SynchronizedRGB(int red, int green, int blue, String name) { check(red, green, blue); this.red = red; this.green = green; this.blue = blue; this.name = name; 60
Classe SynchronizedRGB(2) public void set(int red, int green, int blue, String name) { check(red, green, blue); synchronized (this) { this.red = red; this.green = green; this.blue = blue; this.name = name; public synchronized int getrgb() { return ((red << 16) (green << 8) blue); public synchronized String getname() { return name; public synchronized void invert() { red = 255 - red; green = 255 - green; blue = 255 - blue; name = "Inverse of " + name; 61
Problemi di consistenza una thread A esegue il codice seguente SynchronizedRGB color = new SynchronizedRGB(0,0,0, "Black"); int mycolorint = color.getrgb(); String mycolorname = color.getname(); un altra thread invoca color.set dopo l invocazione a color.getrgb e prima di color.getname la prima thread in mycolorint e mycolorname ha dei dati spuri che possono non corrispondere ad uno stato assunto dall oggetto color 62
Problemi di consistenza Questo problema si può evitare con un blocco sincronizzato synchronized (color) { int mycolorint = color.getrgb(); String mycolorname = color.getname(); In generale, le classi di oggetti immutabili non danno problemi di consistenza e il loro uso è sicuro in ambienti concorrenti 63
Strategia per definire classi immutabili non fornire metodi modificatori rendere le variabili di istanza final e private impedire alle sottoclassi di sovrascrivere metodi classe dichiarata final (semplice) oppure costruttore private e istanziare oggetti attraverso metodi static (sofisticato) se le variabili di istanza contengono riferimenti a oggetti mutabili non far modificare questi oggetti: non fornire metodi che modificano questi oggetti non condividere questi riferimenti fuori della classe (usare clonazione) 64
Classe ImmutableRGB final public class ImmutableRGB { final private int red, green, blue; final private String name; private void check(int red, int green, int blue) { if (red < 0 red > 255 green < 0 green > 255 blue < 0 blue > 255) { throw new IllegalArgumentException(); public ImmutableRGB(int red, int green, int blue, String name) { check(red, green, blue); this.red = red; this.green = green; this.blue = blue; this.name = name; public synchronized int getrgb() { return ((red << 16) (green << 8) blue); public synchronized String getname() { return name; public ImmutableRGMB invert() { return new ImmutableRGB(255 - red, 255 - green, 255 - blue, "Inverse of " + name); 65
API avanzate per la concorrenza oggetti Lock permettono di gestire monitor esplicitamente Strutture dati ad accesso concorrente permettono di ridurre l uso della sincronizzazione Es. BlockingQueue,ConcurrentMap,etc. Variabili Atomic (AtomicInteger, ) evitano errori di consistenza e riducono il ricorso alla sincronizzazione Numeri casuali concorrenti (java.util.concurrent.threadlocalrandom) Executors (Interface,Thread Pools, Fork/Join) high-level API per il lancio e la gestione delle thread 66
Executors in tutti gli esempi visti esiste un collegamento stretto tra il compito svolto da una thread (come definito da Runnable) e la thread stessa (come definita da Thread) va bene per piccole applicazioni per programmi complessi ha senso separare la creazione e la gestione di una thread dal compito svolto dalla thread stessa. gli aspetti di creazione/gestione delle thread sono svolte dagli executors. interfacce Executor: definiscono tre tipi di oggetti executor thread pools: sono le più comuni implementazioni di executor fork/join: è una infrastruttura (nuova in JDK 7) per sfruttare processori multipli 67