j0 1 marco ronchetti java threads & sincronizzazione
Post on 01-May-2015
223 Views
Preview:
TRANSCRIPT
J01
Marc
o R
onch
ett
i
Java
Threads & Sincronizzazione
J02
Marc
o R
onch
ett
i
Threads - cenni di base
Una classe può essere threaded se:
è sottoclasse di Thread
oppure
implementa l’interfaccia Runnable.
In entrambi i casi DEVE implementare il metodo runche viene eseguito quando la thread parte.
J03
Marc
o R
onch
ett
i
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 runboolean f=athread.isAlive(); after start before end
J04
Marc
o R
onch
ett
i
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 runboolean f=athread.isAlive(); after start before end
J05
Marc
o R
onch
ett
i
Thread athreadathread.start() // attiva il metodo runathread.join(anotherThread) //attende la fine di anotherThread…Thread.yield(); //cede la CPU (sospensione non temporizzata) Thread.sleep(long milliseconds); // sospensione temporizzataThread.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 runathread.resume(); // riprende dopo una suspendathread.destroy(); // distrugge la Thread
J06
Marc
o R
onch
ett
i
Daemon Threads
Ci sono due tipi di threads: user threads e daemon threads.
La differenza sta nel fatto che l’applicazione/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 ()
J07
Marc
o R
onch
ett
i
Applet methods - 3import 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(); } }}
J08
Marc
o R
onch
ett
i
Perche’ Threads ?
Nonblocking I/O tecniche standard non disponibili in Java:
I/O multiplexingPollingSignals
Alarms & Timers
Support for (logically) parallel operations
J09
Marc
o R
onch
ett
iControllo delle Threads: rendez-
vous
Class T extends Thread;T t1 = new T();T t2 = new T();
t2.join(); // nel codice di t1sospende l’esecuzione di t1 fino al completamento di t2ovvero fino a quando t2 sara’ considerata “non attiva”
void join();void join(long m); //sospendi, ma per non piu’ di m millisecondsvoid join(long m, int n); //sospendi, ma per non piu’ di
// m milliseconds e n nanoseconds
J010
Marc
o R
onch
ett
i
Behind the scenes
Group Name Description
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() dell’applicazione
J011
Marc
o R
onch
ett
i
Behind the scenes - Applets
Group Name Description
System ---- (come per le applicazioni) -----
AppletViewerAWT-Input gestisce l’input dal windowing
system nativoAWT-Toolkit tratta gli eventi del win. sys. nativoScreen updater gestisce la coda di repaint ed
esegue paint
Image fetcher carica immagini della rete (4 threads)
Audio player gestisce l’output sonoro
AppletNameAppletName Applet Thread (esegue start(0, stop()
ecc.)
J012
Marc
o R
onch
ett
i
Behind the scenes - Applets
In una applet che gestisca immagini e suono, ci sono
almeno 12 threads attive oltre a quella propria della Applet!
J013
Marc
o R
onch
ett
i
Sezione critica
t1 t2 countint k=c.incr(); 0int n = count; 0count= n + 1; 1return n; 1
int k=c.incr(); 1int n = count; 1count= n + 1; 2return n; 2
int k=c.incr(); 2int n = count; 2
int k=c.incr(); 2int n = count; 2count= n + 1; 3return n; 3
count= n + 1; 3return 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); } }}
J014
Marc
o R
onch
ett
i
Sezione critica
t1 t2 countint k=c.incr(); 0int n = count; 0count= n + 1; 1return n; 1
int k=c.incr(); 1int n = count; 1count= n + 1; 2return n; 2
int k=c.incr(); 2int n = count; 2
int k=c.incr();int n = count;count= n + 1;return n;
count= n + 1; 3return 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)); } }}
J015
Marc
o R
onch
ett
i
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”)
J016
Marc
o R
onch
ett
i
Concorrenza: blocchi sincronizzati
A granularita’ piu’ bassa, e’ possibile sincronizzare blocchi di codice su di un monitor.
Nell’esempio a fianco, le sezioni critica di a1,a2,b2 NON possono essere eseguite parallelamente (sono sincronizzate tramite il monitor dell’oggetto 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);
J017
Marc
o R
onch
ett
i
Chiamate sincronizzate ricorsive
...
Class A { synchronized void m1() {
…m2()…
}synchronized void m2() {
…}
Questo codice NON da’ origine a deadlock! La thread PUO’ eseguire m2perche’ GIA’ POSSIEDE il monitor relativo. (Un contatore tiene tracciadi quanti accessi sincronizzati allo stesso monitor vengono fatti).
J018
Marc
o R
onch
ett
i
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.
J019
Marc
o R
onch
ett
i
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 timeoutwait(long msec, int nsec)esegue una wait con timeout
notifyAll() risveglia tutte le threads in attesa sullo stesso monitor(usato ad esempio in MediaTracker)
J020
Marc
o R
onch
ett
i
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) {} } } }}
J021
Marc
o R
onch
ett
i
wait & notify
Attenzione alla perdita di messaggi!
Cosa avviene se la notify()viene inviataprima dellacorrispondentewait() ?
J022
Marc
o R
onch
ett
i
Concorrenza: wait & notify
...
NOTE su wait e notify:wait() rilascia temporaneamente il monitor
Non c’e’ 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
J023
Marc
o R
onch
ett
iProduttore 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.
J024
Marc
o R
onch
ett
i
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) {} }}
J025
Marc
o R
onch
ett
i
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; }}
J026
Marc
o R
onch
ett
i
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"); }}
J027
Marc
o R
onch
ett
i
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();
}}
}
J028
Marc
o R
onch
ett
iProduttore 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
J029
Marc
o R
onch
ett
i
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, vedereOaks and Wong, “Java Threads”,
O’Reilly 1997
J030
Marc
o R
onch
ett
i
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();
}}
J031
Marc
o R
onch
ett
i
Concorrenza: wait & notify
Per approfondimenti vedere…
Si rimanda a “Java Threads”Di Oaks e WongEd. O’Reilly
“Java Restaurant”Ed. Apogeo
top related