J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

31
J0 1 Marco Ronchetti Java Threads & Sincronizzazione

Transcript of J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

Page 1: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

J01

Marc

o R

onch

ett

i

Java

Threads & Sincronizzazione

Page 2: J0 1 Marco Ronchetti 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.

Page 3: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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

Page 4: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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

Page 5: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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

Page 6: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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 ()

Page 7: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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(); } }}

Page 8: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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

Page 9: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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

Page 10: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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

Page 11: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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.)

Page 12: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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!

Page 13: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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); } }}

Page 14: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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)); } }}

Page 15: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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”)

Page 16: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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);

Page 17: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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).

Page 18: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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.

Page 19: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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)

Page 20: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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) {} } } }}

Page 21: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

J021

Marc

o R

onch

ett

i

wait & notify

Attenzione alla perdita di messaggi!

Cosa avviene se la notify()viene inviataprima dellacorrispondentewait() ?

Page 22: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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

Page 23: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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.

Page 24: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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) {} }}

Page 25: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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; }}

Page 26: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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"); }}

Page 27: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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();

}}

}

Page 28: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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

Page 29: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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

Page 30: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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();

}}

Page 31: J0 1 Marco Ronchetti Java Threads & Sincronizzazione.

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