Priorità e Sincronizzazione tra Threads Priorità e preemption • Java non garantisce la preemption • Lo scheduling avviene in base all’algortimo Highest Priority First • Un thread interrompe l’esecuzione se: – Esce dal proprio metodo run() – Si sospende invocando sleep(), wait() oppure è in attesa di I/O – Cede la CPU invocando yield() – Entra nel sistema un thread a priorità maggiore sleep((long)(Math.random() * 1000)); Se il thread etra nello stato Not Runnable, vi è sempre una specifica modalità per tornare nello entra stato nello Runnable Un thread stato :Not Runnable se uno dei seguenti eventi si verifica: • Se il thread sleep è statoè disposto •Il metodo invocato.nello stato di sleep(), dopo che un determinato numero di millisecondi è terminato. •Il thread chiama il metodo wait in attesa che una specifica condizione sia • Se il thread è in stato di wait(), si attende che un altro oggetto notifichi la soddisfatta. condizione thread inin attesa •Il thread al è bloccato I/O. con notify() o notifyAll(). Altri dettagli in Synchronizing Threads. • Se un thread è bloccato in I/O, occorre attendere che l’I/O completi Un programma non ferma un thread come avviene con un Applet attraverso la chiamata di un metodo. Un thread provoca la propria morte attraverso la terminazione naturale del metodo run. public void run() { Causa pausa forla(int i = 0; temporanea i < 10; i++) { del thread correntemente in esecuzione e Metodo isAlive permette ad altri thread di+essere eseguiti. System.out.println(i " + getName()); Il metodo isAlive restituisce" true se il thread è in stato Runnable o Not try { Runnable.sleep((long)(Math.random() Se il metodo isAlive restituisce false, il thread è un nuovo thread * 1000)); oppure }ècatch morto. Non è possibile distinguire tra un nuovo thread e un thread (InterruptedException e) {} morto} e tra un thread Runnable e un thread Not Runnable. System.out.println("DONE! " + getName()); } Thread Priority Thread 1 priority Thread 2 Thread 1 Thread 2 1 CPU PREEMPTION fixed priority scheduling. Scheduler esegue il thread con più alta priorità Quando thread si • Un thread a piùil alta ferma, yields, o diventa priorità diventa runnable. Not Runnable, un thread •Il thread yields, oppure il a bassarun priorità inizierà suopiù metodo termina l’esecuzione •Su sistemi che Se due thread con supportano partizione di stessa priorità sono in tempo, la frazione di attesa di essere eseguiti, tempo allocata è lo scheduler li esegue con terminata politica round-robin. • The Java runtime will not preempt the currently running thread for another thread of the same priority. In other words, the Java runtime does not time-slice. However, the system implementation of threads underlying the Java Thread class may support time-slicing. Do not write code that relies on time-slicing. • In addition, a given thread may, at any time, give up its right to execute by calling the yield method. Threads can only yield the CPU to other threads of the same priority--attempts to yield to a lower priority thread are As you can imagine, writing CPU-intensive code can ignored. have negative repercussions on other threads runningthreads in the same In general, youpriority, should the • When all the runnable in theprocess. system have the same to next writethread "well-behaved" voluntarily scheduler choosestrythe to run in athreads simple,that non-preemptive, relinquish the CPU periodically and give other round-robin scheduling order. threads an opportunity to run. In particular, you should never write Java code that relies on timesharing--this will practically guarantee that your program will give different results on different computer systems. Sincronizzazione Balance = 15; if (Balance – 10 >= 0) Thread1 If( … ) Balance -= 10; Thread2 If( … ) Balance -=10 Balance -=10 Balance 15 15 5 -5 !! Sincronizzazione/1 1. Uso di blocchi synchronized 2. Uso dei metodi wait() e notify() (appartengono alla classe Object) • Noi vediamo synchronized Sincronizzazione/2 • E’ necessario che un solo thread alla volta possa eseguire il blocco di codice • Ciò può essere dichiarato con la sintassi seguente: synchronized ((Integer) Balance) { if (Balance – 10 >= 0) } Balance -= 10; Sincronizzazione/3 • Il thread che esegue per primo l’istruzione synchronized acquisisce il controllo (lock) dell’oggetto Balance • Il lock è rilasciato all’uscita del blocco • Nessun altro thread può eseguire istruzioni del blocco senza aver prima acquisito il lock sull’oggetto Sincronizzazione/4 • Si possono dichiarare metodi synchronized (anche statici) class myClass { private int myVar; public synchronized void myMethod(int newVal) { myVar = newVal; } ...... • Solo un thread alla volta può modificare myVar (quello che ottiene il lock sull’oggetto di tipo myClass) Thread Sincronizzati Thread separati devono considerare la condivisione di dati e lo stato di attività degli altri Threads. Occorre comunque sincronizzare threads che condividono una risorsa Thread A Thread B write read Produttore/Consumatore sleep(random) PRODUCER i k Il consumatore non deve acedere il cubbyhole quando viene modificato dal produttore, e il produttore non deve modificarlo quando il consumatore sta accedendo get, put methods synchronized. CONSUMER i i cubbyhole.get() cubbyhole.put(i) cubbyhole synchronized Skeleton public class CubbyHole { private int contents; private boolean available = false; public synchronized int get() { ... } public synchronized void put(int value) { ... } } public synchronized void put(int value) { // CubbyHole locked by the int Producer public synchronized get() { .. // CubbyHole locked by the Consumer // CubbyHole unlocked by the Producer ... } // CubbyHole unlocked by the Consumer } Il sistema associa un unico lucchetto ad ogni istanza di CubbyHole (compresa quella condivisa dal produttore e dal consumatore). Quando il controllo invoca un metodo sincronizzato, il thread che ha chiamato questo metodo blocca l’oggetto su cui il metodo è stato invocato. Gli altri threads non possono chiamare un metodo sincronizzato sullo stesso oggetto finchè l’oggetto non è rilasciato. i PRODUCER put i L’acquisizione ed il rilascio di un lucchetto è realizzato automaticamente ed in modo atomico dal sistema runtime di Java. Questo evita corse critiche ell’implementazione dei threads e l’integrità dei dati. La sincronizzazione non conclude la questione. Due thread devono anche essere in grado di notificare reciprocamente l’avvenuto svolgimento di un compito. public synchronized int get() { if (available == true) { available = false; return contents; } } Cosa succede se il produttore non ha disposto alcun oggetto nel Cubbyhole e available non è true? get non fa nulla public synchronized void put(int value) { if (available == false) { available = true; contents = value; } } Se il produttore invoca put prima che il consumatore ottenga il valore, non si ha nessun valore nel Cubbyhole. WAIT & NOTIFYALL private boolean available = false public synchronized int get() { while (available == false) { try { // wait for Producer to put value wait(); } catch (InterruptedException e) { } } available = false; // notify Producer that value has been retrieved notifyAll(); return contents; } public synchronized void put(int value) { while (available == true) { try { // wait for Consumer to get value wait(); } catch (InterruptedException e) { } } contents = value; available = true; // notify Consumer that value has been set notifyAll(); } Ilmetodo notifyAll risveglia tutti i threads in attesa sull’oggetto in questione. I threads notificati competono per il lock.Il Un thread otterrà metodo wait l’oggetto, rilasciamentre il lock gli altri torneranno stato di attesa. ottenutoindal Il consumatore esce La classe Object anche consumatore sul dalloun stato di wait, definisce metodo notify, CubbyHole e availablearbitrariamente è ora true, il che quindi risveglia attende la loop termina ed il une notifica dei thread del in attesa metodo get restituisce il sull’oggetto. produttore valoreQuando nel Cubbyhole. il produttore wait dispone qualcosa nel CubbyHole, notifica il consumatore atraverso notifyAll Il produttore può ottenere il lock e qundi aggiornare il CubbyHole