IL PROBLEMA DELLA MUTUA ESCLUSIONE i=0 thread 1 thread 2 class Count { int i = 0; void incr() { i+1 1 i = i + 1; i -1 -1 } i=1 void decr() { i = -1 i = i - 1; } } Il valore finale di i dipende dalla sequenza di esecuzione METODI synchronized Il modificatore synchronized prescrive che il metodo a cui si applica sia eseguito da un solo thread alla volta: quando un thread esegue un metodo synchronized, viene fatto un lock dell’oggetto cui appartiene il metodo (o, per metodi static, della classe) quando il thread termina l’esecuzione l esecuzione del metodo, viene fatta una unlock prima di tale unlock, eventuali altri metodi synchronized si pongono in attesa 1 ESEMPIO i=0 thread 1 thread 2 class Count { int i = 0; synchronized void incr() { i+1 1 i = i + 1; i=1 } synchronized y void decr() () { i -1 0 i = i - 1; i=0 } } Il valore finale di i NON dipende dalla sequenza di esecuzione ESEMPIO import java.util.Vector; public class MsgQueue { Vector queue = new Vector(); public synchronized void send(Object obj) { queue.addElement(obj); } public synchronized Object receive() { if (queue.size() == 0) return null; Object obj = queue.firstElement(); queue.removeElementAt(0); return obj; } } 2 ESEMPIO class ExThread extends Thread { private static int countDown = 5; public static void main(String args[]) { ExThread t1,t2; t1 = new ExThread("Castore"); t1.start(); t2 = new ExThread("Polluce"); t2.start(); } public ExThread(String str) { super(str); } public void run() { System.out.println(getName() + ": via!"); while(true) { System.out.println("Thread " +getName() + "(" + countDown + ")"); if(--countDown == 0) return; } } } ESEMPIO public class TestThread { public static void main(String args[]) { ExThread2 t1,t2; t1 = new ExThread2("Castore"); t1.start(); t2 = new ExThread2("Polluce"); t2.start(); }} class ExThread2 extends Thread { static int countDown = 15; public ExThread2(String str) { super(str);} synchronized static int dec () { countDown--; return countDown; } public void run() { int x=0; System.out.println(getName() + ": via!"); while((x=dec())>=0) { System.out.println("Thread " +getName() + "(" + (x+1) + ")"); }} } 3 Monitor in java • Caratteristiche principali dei monitor Java – ME nell’esecuzione dei metodi synchronized – non ci sono variabili di condizione – wait(), notify() simili a sleep() , wakeup() I monitor e la sincronizzazione di thread in java In Java, la sincronizzazione di thread per l’accesso concorrente ad oggetti condivisi si ottiene utilizzando i seguenti costrutti linguistici: • metodi synchronized • i metodi wait() , notify() e notifyAll() Quando una classe C dichiara alcuni metodi come synchronized essa equivale ad un monitor. Se l’oggetto o è un’istanza di C, è garantita l’esecuzione in mutua esclusione (da parte di thread diversi che condividono l’oggetto) di tutti i metodi synchronized (sullo stesso oggetto o). L differenze Le diff principali i i li rispetto i tt aii monitor it sono: • nella stessa classe possono convivere sia metodi synchronized sia metodi non synchronized • i metodi wait() e notify() corrispondono a wait() e signal() ma non sono associati ad una condition (esiste una sola coda di attesa) 4 wait, notify Sono metodi della classe Object: public final void wait(); public final void wait(long millis); public final void notify(); /* rilascia il lock e si pone in wait */ /* wait con timeout */ //* rilascia il lock e sveglia un singolo thread*/ Monitor e Semafori a confronto I monitor costituiscono un meccanismo di sincronizzazione di più alto livello rispetto ai semafori, semafori tuttavia qualsiasi problema di sincronizzazione risolto con i semafori può essere risolto con i monitor e viceversa: lo si dimostra facendo vedere come si può realizzare un semaforo attraverso i monitor e viceversa. 5 Realizzazione dei semafori tramite i monitor type semaforo = monitor; var semaforo_positivo:condition; p g var val, sospesi:integer; procedure entry init(valore_iniziale) { val = valore_iniziale; } procedure entry down() { if (val==0) {sospesi = sospesi+1; semaforo positivo wait; semaforo_positivo.wait; sospesi = sospesi-1;} else { val = val –1;} } procedure entry up() { if (sospesi>0) { semaforo_positivo.signal;} else { val = val +1;} } { /*Inizializzazione */ val = 0; sospesi = 0; } Semafori in Java public class Semaphore { private int value, sospesi; public Semaphore (int v) { value=v; sospesi=0;} public bli synchronized h i d void id down d () { if (value==0) { sospesi++; try { wait()}; catch (InterruptedExeception e {} sospesi--;} else { value--;; } } public synchronized void up () { if (sospesi>0) { notify(); } else{ value++;} } 6 Uso dei monitor in java Soluzione per Produttore/Consumatore in Java (parte 1) Uso dei monitor in java Soluzione per Produttore/Consumatore in Java (parte 2) 7