Scaricare la presentazione
La presentazione è in caricamento. Aspetta per favore
PubblicatoGoffredo Maggio Modificato 11 anni fa
1
J0 1 Marco Ronchetti Java Threads & Sincronizzazione
2
J0 2 Marco Ronchetti Threads - cenni di base Una classe può essere threaded se: è sottoclasse di Thread oppure implementa linterfaccia Runnable. In entrambi i casi DEVE implementare il metodo run che viene eseguito quando la thread parte.
3
J0 3 Marco Ronchetti Threads - cenni di base Public class C extends Thread { public void run() { //implementazione di run } } Nel codice di una Classe che usa C: … C athread = new C(); athread.start(); // attiva il metodo run boolean f=athread.isAlive(); after start before end
4
J0 4 Marco Ronchetti Threads - cenni di base Public class C implements Runnable { public void run() { //implementazione di run } } Nel codice di una Classe che usa C: … C aRunnableClass = new C(); Thread athread = new Thread(aRunnableClass); athread.start(); // attiva il metodo run boolean f=athread.isAlive(); after start before end
5
J0 5 Marco Ronchetti Thread athread athread.start()// attiva il metodo run athread.join(anotherThread) //attende la fine di anotherThread … Thread.yield(); //cede la CPU (sospensione non temporizzata) Thread.sleep(long milliseconds); // sospensione temporizzata Thread.sleep(long milliseconds, int nanoseconds); athread.setDaemon(); athread.isDaemon() //analogo ai demoni unix Metodi principali di Thread METODI DEPRECATI! athread.stop();// interrompe il metodo run (termina) athread.suspend();// sospende indefinitamente il metodo run athread.resume();// riprende dopo una suspend athread.destroy();// distrugge la Thread
6
J0 6 Marco Ronchetti Daemon Threads Ci sono due tipi di threads: user threads e daemon threads. La differenza sta nel fatto che lapplicazione/applet termina quando non ci sono piu user threads. Le daemon threads servono dunque per effettuare servizi a favore delle user threads. Tutte le threads di sistema sono daemon threads. void setDaemon(boolean on) boolean isDaemon ()
7
J0 7 Marco Ronchetti Applet methods - 3 import java.awt.Graphics; import java.util.Date; public class ShowAppletMethods extends java.applet.Applet { Date d; static int count=0; simpleThread t; public void init() { System.out.println((count++)+" Init Executed"); int seconds=Integer.parseInt(this.getParameter( "Secondi")); t=new simpleThread(this,seconds); t.start(); } public void start() { System.out.println((count++)+" Start Executed"); } public void stop() { System.out.println((count++)+" Stop Executed"); } public void destroy() { System.out.println((count++)+" Destroy Executed"); } public void paint(Graphics g) { System.out.println((count++)+" Paint Executed"); d=new Date(); g.drawString("Time now is "+d.getHours() +":" +d.getMinutes() +":" +d.getSeconds(), 5, 25); } class simpleThread extends Thread { ShowAppletMethods a; int seconds; simpleThread(ShowAppletMethods a, int s) { this.a=a; seconds=s*1000; } public void run() { while (true) { try { sleep(seconds); } catch (InterruptedException e) {} System.out.println("==> THREAD: calling repaint"); a.repaint(); }
8
J0 8 Marco Ronchetti Perche Threads ? Nonblocking I/O tecniche standard non disponibili in Java: I/O multiplexing Polling Signals Alarms & Timers Support for (logically) parallel operations
9
J0 9 Marco Ronchetti Controllo delle Threads: rendez-vous Class T extends Thread; T t1 = new T(); T t2 = new T(); t2.join(); // nel codice di t1 sospende lesecuzione di t1 fino al completamento di t2 ovvero fino a quando t2 sara considerata non attiva void join(); void join(long m); //sospendi, ma per non piu di m milliseconds void join(long m, int n); //sospendi, ma per non piu di // m milliseconds e n nanoseconds
10
J0 10 Marco Ronchetti Behind the scenes Group NameDescription System Clock handler gestisce sleep e wait(timeout) Idle thread attiva il garbage collector Garbage Collector libera gli oggetti non usati Finalizer Thread gestisce il metodo finalize() sugli oggetti liberati Main Main esegue il metodo main() dellapplicazione
11
J0 11 Marco Ronchetti Behind the scenes - Applets Group NameDescription System ---- (come per le applicazioni) ----- AppletViewer AWT-Input gestisce linput dal windowing system nativo AWT- Toolkit tratta gli eventi del win. sys. nativo Screen updater gestisce la coda di repaint ed esegue paint Image fetcher carica immagini della rete (4 threads) Audio player gestisce loutput sonoro AppletName AppletName Applet Thread (esegue start(0, stop() ecc.)
12
J0 12 Marco Ronchetti Behind the scenes - Applets In una applet che gestisca immagini e suono, ci sono almeno 12 threads attive oltre a quella propria della Applet!
13
J0 13 Marco Ronchetti Sezione critica t1t2count int k=c.incr();0 int n = count;0 count= n + 1;1 return n;1 int k=c.incr();1 int n = count;1 count= n + 1;2 return n;2 int k=c.incr();2 int n = count;2 int k=c.incr();2 int n = count;2 count= n + 1;3 return n;3 count= n + 1;3 return n;3 package counter; import java.io.*; class Counter { private int count = 0; int maxiter=233; public int incr() { int n = count; delay(maxiter); count= n + 1; return n; } public void delay(int maxiter) { double z=1; for (int k=0;k<maxiter;k++) { z = Math.sqrt(Math.sin(Math.random()*z)); } public class CounterUser { public static void main(String arg[]) { Counter cont=new Counter(); T t1 = new T(cont); T t2 = new T(cont); t1.start();A t2.start(); } class T extends Thread { Counter c; T(Counter c) { this.c=c; } public void run() { int k=0; while (true) { k=c.incr(); System.out.println(this.toString()+" - "+k); c.delay(20*c.maxiter); }
14
J0 14 Marco Ronchetti Sezione critica t1t2 count int k=c.incr();0 int n = count;0 count= n + 1;1 return n;1 int k=c.incr();1 int n = count;1 count= n + 1;2 return n;2 int k=c.incr();2 int n = count;2 int k=c.incr(); int n = count; count= n + 1; return n; count= n + 1;3 return n;3 package counter; import java.io.*; class Counter { private int count = 0; int maxiter=233; public syncronized int incr() { int n = count; delay(maxiter); count= n + 1; return n; } public void delay(int maxiter) { double z=1; for (int k=0;k<maxiter;k++) { z = Math.sqrt(Math.sin(Math.random()*z)); }
15
J0 15 Marco Ronchetti Concorrenza: metodi sincronizzati Una sola thread alla volta puo eseguire un metodo synchronized su un dato oggetto (su oggetti diversi sono possibili esecuzioni parallele di metodi synchronized!) Concetto di MONITOR (Analogia: bastone della staffetta) OGNI OGGETTO POSSIEDE UN MONITOR! (ma anche le Classi possono possedere un monitor, per i metodi static)
16
J0 16 Marco Ronchetti Concorrenza: blocchi sincronizzati A granularita piu bassa, e possibile sincronizzare blocchi di codice su di un monitor. Nellesempio a fianco, le sezioni critica di a1,a2,b2 NON possono essere eseguite parallelamente (sono sincronizzate tramite il monitor delloggetto o1. La sezione critica di b1 invece puo essere eseguita in parallelo a quelle di a1,a2,b2 perche si sincronizza con un diverso monitor. class A { public void doSomething(Object o) { … synchronized(o) { sezione critica di A }... } class B { public void doSomethingElse(Object k) { … synchronized(k) { sezione critica di B }... } … Point o1 = new Point(); A a1=new A(); A a2=new A(); B b1=new B(); B b2=new B(); da thread diverse, vengono invocati: a1.doSomething(o1); b1.doSomethingElse(this); a2.doSomething(o1); b2.doSomethingElse(o1);
17
J0 17 Marco Ronchetti Chiamate sincronizzate ricorsive... Class A { synchronized void m1() { … m2() … } synchronized void m2() { … } Questo codice NON da origine a deadlock! La thread PUO eseguire m2 perche GIA POSSIEDE il monitor relativo. (Un contatore tiene traccia di quanti accessi sincronizzati allo stesso monitor vengono fatti).
18
J0 18 Marco Ronchetti Soluzioni per il problema della concorrenza Soluzioni classiche: Monitors + condition variables (Hoare-Hansen 74/75) Monitor: una collezione di procedure, variabili e strutture dati raccolte in uno speciale modulo, con la proprietà che un solo processo alla volta può eccedere ad un monitor. C.V.: Variabili con due primitive: wait e notify. wait mette il processo in attesa sulla c.v. notify risveglia un processo in attesa sulla c.v.
19
J0 19 Marco Ronchetti Concorrenza: wait & notify... synchronized (pippo) { while (! condizione) { pippo.wait(); } synchronized (pippo) { pippo.notify();// risveglia il primo in coda su pippo } wait(long msec)esegue una wait con timeout wait(long msec, int nsec)esegue una wait con timeout notifyAll() risveglia tutte le threads in attesa sullo stesso monitor (usato ad esempio in MediaTracker)
20
J0 20 Marco Ronchetti wait & notify class Pong extends Thread { Object monitor1,monitor2; Pong(Object o1,Object o2) { this.monitor1=o1; this.monitor2=o2; } public void run() { while (true) { synchronized(monitor1) { try{ System.out.println("<< == Pong is waiting"); monitor1.wait(); } catch (InterruptedException e) {} } System.out.println("<< Pong"); synchronized(monitor2) { System.out.println("<< == Pong is notifying"); monitor2.notify(); } public class PingPong { //Main method PingPong() { Object z1=new Object(); Object z2=new Object(); Ping t1=new Ping(z1,z2); Pong t2=new Pong(z1,z2); t1.start(); t2.start(); try { Thread.sleep(60*1000); } catch (InterruptedException i) {} t1.stop(); t2.stop(); } public static void main (String[] args) { new PingPong (); } class Ping extends Thread { Object monitor1,monitor2; Ping(Object o1,Object o2) { this.monitor1=o1; this.monitor2=o2; } public void run() { while (true) { try { Thread.sleep(1000); } catch (InterruptedException i) {} System.out.println(">> Ping"); synchronized(monitor1) { System.out.println(">> == Ping is notifying"); monitor1.notify(); } synchronized(monitor2) { try{ System.out.println(">> == Ping is waiting"); monitor2.wait(); } catch (InterruptedException e) {} }
21
J0 21 Marco Ronchetti wait & notify Attenzione alla perdita di messaggi! Cosa avviene se la notify() viene inviata prima della corrispondente wait() ?
22
J0 22 Marco Ronchetti Concorrenza: wait & notify... NOTE su wait e notify: wait() rilascia temporaneamente il monitor Non ce modo di distinguere se da una wait si e usciti per timeout o per notification esecuzioni di wait o notify senza acquisizione del monitor danno origine a IllegalMonitorStateException
23
J0 23 Marco Ronchetti Produttore e consumatore con buffer Problema classico: Due processi (Produttore e Consumatore) collaborano, scambiandosi dati tramite un buffer condiviso. Occorre evitare che : - il Produttore tenti di scrivere se il buffer e pieno, - il Consumatore tenti di leggere se il buffer e vuoto.
24
J0 24 Marco Ronchetti Produttore e Consumatore package ProCon; public class ProCon { ProCon() throws InterruptedException { Buffer b = new Buffer(10); Consumer c = new Consumer(b,600); Producer p = new Producer(b,300); Thread tc = new Thread(c); Thread pc = new Thread(p); tc.start(); pc.start(); pc.join(); tc.join(); System.out.println("ProCon resuming execution..."); synchronized (this) { wait(3000); } public static void main(String[] args) { try { ProCon p = new ProCon(); } catch (Exception w) {} }
25
J0 25 Marco Ronchetti Produttore e Consumatore package ProCon; public class Buffer { private char[] buf; // buffer storage private int last; // last occupied position public Buffer(int sz) { buf = new char[sz]; last = 0; } public boolean isFull() { return (last == buf.length); } public boolean isEmpty() { return (last == 0); } public synchronized void put(char c) { while(isFull()) { // wait for room to put stuff try { wait(); } catch(InterruptedException e) { } } buf[last++] = c; notify(); } public synchronized char get() { while(isEmpty()) { // wait for stuff to read try { wait(); } catch(InterruptedException e) { } } char c = buf[0]; System.arraycopy(buf, 1, buf, 0, --last); notify(); return c; }
26
J0 26 Marco Ronchetti Produttore e Consumatore package ProCon; public class Consumer implements Runnable { private Buffer buffer; private int delay=0; public Consumer(Buffer b, int d) { buffer = b; delay = d; } public void run() { for (int i=0; i<52; i++) { System.out.println("Consuming "+buffer.get()); try { Thread.sleep(delay); } catch (InterruptedException ie){} } System.out.println("Consumer Ended"); } package ProCon; public class Producer implements Runnable { private Buffer buffer; private int delay=0; public Producer(Buffer b, int d) { buffer = b; delay = d; } public void run() { for (int i=0; i<52; i++) { char c = (char)('A' + (i%26)); System.out.println("Producing "+c); buffer.put(c); // write to the buffer try { Thread.sleep(delay); } catch (InterruptedException ie){} } System.out.println("Producer Ended"); }
27
J0 27 Marco Ronchetti Semafori con i monitor public class Semaphore { private int S=0; private int waitingProcesses=0; Semaphore(int v) { S=v; } public synchronized void down() { if (S>0) S--; else { try { waitingProcesses++; wait(); } catch (InterruptedException e) {} } public synchronized void up() { if (waitingProcesses == 0) S++; else { waitingProcesses --; notify(); }
28
J0 28 Marco Ronchetti Produttore e Consumatore coi semafori public class ProCon { ProCon() throws InterruptedException { Buffer b = new Buffer(10); Consumer c = new Consumer(b,600); Producer p = new Producer(b,300); Thread tc = new Thread(c); Thread pc = new Thread(p); tc.start(); pc.start(); pc.join(); tc.join(); System.out.println("ProCon resuming execution..."); synchronized (this) { wait(3000); } public static void main(String[] args) { try { ProCon p = new ProCon(); } catch (Exception w) {} } public class Buffer { private char[] buf; // buffer storage private int last; // last occupied position Semaphore empty; Semaphore full; Semaphore mutex; public Buffer(int sz) { buf = new char[sz]; last = 0; empty=new Semaphore(sz); full=new Semaphore(0); mutex=new Semaphore(1); } public void put(char c) { empty.down(); mutex.down(); buf[last++] = c; mutex.up(); full.up(); } public char get() { full.down(); mutex.down(); char c = buf[0]; System.arraycopy(buf, 1, buf, 0, --last); mutex.up(); empty.up(); return c; } Le classi producer e consumer non cambiano
29
J0 29 Marco Ronchetti Threads scheduling Lo scheduling della JVM e inaffidabile (perché ancora indefinito), nel senso che cambiando piattaforma cambia implementazione. Se serve uno scheduling con proprietà ben definite e bene scrivere il proprio scheduler. Per dettagli, vedere Oaks and Wong, Java Threads, OReilly 1997
30
J0 30 Marco Ronchetti A simple Round Robin scheduler public class SimpleScheduler extends Thread { int timeslice; public SimpleScheduler(int t) { timeslice=t; setPriority(Thread.MAX_PRIORITY); setDaemon(true); } public void run() { while (true) try { sleep(timeslice); } catch (Exception e) {} } class TestThread extends Thread { public void run() {... } public class Test { public static void main (string args[]) { new SimpleScheduler(100).start(); TestThread t1,t2,t3; t1=new TestThread(); t2=new TestThread(); t3=new TestThread(); t1.start(); t2.start(); t3.start(); }
31
J0 31 Marco Ronchetti Concorrenza: wait & notify Per approfondimenti vedere… Si rimanda a Java Threads Di Oaks e Wong Ed. OReilly Java Restaurant Ed. Apogeo
Presentazioni simili
© 2024 SlidePlayer.it Inc.
All rights reserved.