You are on page 1of 54

Guido Massa Finoli Programmazione Java con Threads

1
Programmazione java con threads
Indice:
1) Struttura dei Thread e modelli di ottimizzazione
2) Come si crea un Thread
3) Attivit e Metodi della Classe Thread
4) Schedulazione dei Threads
5) Sincronizzazione dei Threads
6) Esempio tipico, problema produttore/consumatore
7) Particolarit dei Threads
8) Esempio di Automa Cellulare utilizzando Threads
Caso A)
Caso B)
9) Simulazione sistema automatico di produzione
Guido Massa Finoli Programmazione Java con Threads
2
1) Struttura dei Thread e modelli di ottimizzazione
Un Thread un modo per suddividere un programma in unit ancora pi semplice, quindi un
modo per avere una unit di esecuzione ancora pi elementare di un programma. Uno sviluppo
senza Th associa ad un programma un processo, mentre la creazione di Th permette lassociazione
di un processo al TH, quindi un programma suddiviso in Th viene eseguito su pi processi che
possono eseguiti contemporaneamente, utilizzando il servizio multitasking del sistema operativo.
Questa suddivisione pu essere effettuata su parti differenti del programma che possono essere
eseguite contemporaneamente oppure una stessa parte che pu essere eseguita su uno o pi processi
contemporaneamente. Questo permette la condivisione di risorse come la memoria, i servizi I/O ed
un efficiente utilizzo della CPU.
Ad esempio immaginiamo un programma che legge un file e lo elabora nella CPU, lelaborazione
con un PGM con 1 Th dura totalmente 7 secondi.
1 2 3 4 5 6 7
compute Readfile compute readfile compute readfile compute
CPU
busy busy busy busy
Come si vede la CPU occupata solo per 4 secondi su 7, ovvero lo 0,57%.
Se la stessa esecuzione la suddividiamo su 2 Th allora abbiamo nel primo caso un utilizzo totale
della CPU di 14 sec., con una esecuzione reale di 8 sec. Con una efficienza del 57%.
Nel caso di 2 Th avremo:teoricamente un utilizzo al 100% della CPU in quanto i due Th possono
sovrapporsi nella loro esecuzione:
CPU
busy busy busy busy
busy busy busy busy
Quindi una programmazione a multi-thread ha sicuramente tutta una serie di vantaggi rispetto ad
una programmazione senza Thread:
1) Miglioramente delle performance di esecuzione del programma
2) Tempi di attesa dellutente ridotti
3) Uso efficiente delle risorse condivise del sistema
4) Una modellizzazione del programma pi semplice
Ma sicuramente essa ha in se anche alcuni problemi, il principale che il programmatore non deve
solo analizzare lesecuzione della procedura come in qualsiasi linguaggio, ma deve analizzare anche
lesecuzione dei singoli Th per verificare che siano tra di loro compatibili nellutilizzo delle risorse,
quindi organizzare un ordine di gerarchie, di computibilit, ecc.
In definitiva occorre anche una programmazione dei Th il cui criterio finale quello di ottimizzare
tutte le variabili che gestiscono una procedura.
Risorse Accessibili:
a) CPU
b) I/O su disco
Guido Massa Finoli Programmazione Java con Threads
3
c) I/O su Video
d) Output su Stampante
Quando un PGM viene avviato sempre gi presente un Thread in esecuzione, rappresentato dal
TH Principale attivato dal main( String arg[]) ed esso ha 2 fondamentali aspetti:
1) Tutti i TH creati dal programmatore saranno figli del TH Main
2) Il TH Main deve essere sempre lultimo TH del PGM ad essere chiuso
Il TH Main pur essendo automaticamente creato, pu essere comunque gestito e controllato, ed
innanzi tutto pu essere acquisito attraverso il metodo:
Static Thread currentThread()
2) Come si crea un Thread
Attraverso la Classe Thread o una Interfaccia runnable
Guido Massa Finoli Programmazione Java con Threads
4
Per creare un nuovo TH il PGM deve estendere la Classe Thread oppure implementare linterfaccia
runnable.
Quindi data la classe Thread abbiamo:
a) Dichiarare una sottoclasse di Thread
b) Sovrascrivere il metodo run()
c) Creare un Oggetto della sottoclasse
d) Invocare il metodo start()
public class Thread
{
public void run(){};
}
Qundi abbiamo :
Dichiarazione di una sottoclasse di Th e sovrascrittura metodo run()
public class EsThread extends Thread {
public void run(){};
}
Creazione di un oggetto della sottoclasse di Th e chiamata di start()
EsThread T = new EsThread();
T.start();
Dato linterfaccia Runnable abbiamo:
a) Creare una classe che implementa Runnable
b) Creare un Oggetto della classe
c) Creare un Oggetto della classe Thread passando al costruttore lOggetto della classe
implementazione di Runnable
d) Attivare lOggetto con il metodo start()
Creazione di una classe che implementa runnable()
public class EsRunnable extends Runnable {
public void run(){};
}
Creazione oggetto di tipo runnable(), creazione di un oggetto di tipo Thread e passaggio come
parametro delloggetto runnable()
EsRunnable MioR = new EsRunnable;
EsThread T = new EsThread(MioR);
T.start();
3) Attivit e Metodi della Classe Thread
Guido Massa Finoli Programmazione Java con Threads
5
getName() Ottiene il nome di un Thread
get Priority() Ottiene la priorit di un Thread
isAlive() Determina se un Thread ancora attivo
join() Esegue fino alla fine il Thread
resume() Riattiva un Thread
run() Punto di esecuzione di un Thread
sleep() Sospende un Thread per un tempo definito
start() Attivazione di un Thread
suspend() Sospende un Thread per un tempo definito
Java thread can
be in one of
these states
new TH allocato e in attesa di esecuzione
runnable TH in attesa di essere eseguito
run TH in esecuzione
blocked TH in attesa di un evento esterno
timed_waiting TH stato di attesa definito temporalmente
dead TH finito
Guido Massa Finoli Programmazione Java con Threads
6
Come si vede il passaggio da uno stato e laltro pu essere dato dallapplicazione di un metodo,
oppure dallo stato di utilizzo delle risorse disponibili. Quando non sono utilizzati esplicitamente dei
metodi per gestire i Thread sar la macchina ad occuparsi della loro esecuzione secondo criteri
NON DETERMINISTICI e in parte dipendenti dal modo in cui sono stati configurati i Thread.
Connessione tra Stati e Metodi meglio specificata:
Come si vede gli stati di un Thread (ready, running, slepping, blocked, waiting, dead) sono collegati
a metodi oppure alla schedulazione in attesa di allocare una risorsa. Se non viene definita una
priorit nella esecuzione o un ordine attraverso luso di metodi, lelaborazione dei TH simultanei
avviene in maniera casuale, non deterministica.
Guido Massa Finoli Programmazione Java con Threads
7
Quando un thread creato (New Thread) nel suo stato iniziale un empty Thread object; nessuna
risorsa di sistema allocata per esso. Quando un thread in questo stato, su di esso pu essere
invocato il metodo start(); se start invocato su un oggetto thread che non si trova in tale stato
iniziale si causa leccezione
Il metodo start crea le risorse di sistema necessarie per eseguire il thread, schedula il thread per
eseguirlo, e chiama il metodo run() della classe thread; dopo il return di start il thread Runnable
Un thread che inizializzato con start() nello stato Runnable. In genere i computer hanno un solo processore,
quindi i threads vanno eseguiti uno per volta.. Il Java runtime system deve implementare uno schema di
scheduling scheme che permette la condivisione del processore fra tutti i "running" threads, cos, ad un dato
istante un solo running thread realmente in esecuzione, gli altri sono in waiting per il loro turno di CPU.
Un thread diventa Not Runnable (o blocked) quando:
1) Il thread chiama il metodo wait() per aspettare che una specifica condizione sia soddisfatta.
2) Il thread bloccato su un I/O.
Per ogni entrata in un Not Runnable , c una specifica e distinta azione che permette il ritorno nello
stato di Runnable:
1) Se un thread stato posto in wait, il numero specifico di millisecondi deve trascorrere.
2) Se un thread in attesa per una condizione, allora un altro oggetto deve notificare il thread in
attesa di un cambio nelle condizioni chiamando notify o notifyAll
3) Se un thread blocked su I/O, allora lI/O deve essere completato
Nota : Un programma non termina un thread attraverso la chiamata di un metodo; piuttosto, un
thread termina naturalmente (dead) quando il metodo run termina (exit)
isAlive()
isAlive()
Thread
True
Runnable o
Not Runnable
New o Dead
False
Guido Massa Finoli Programmazione Java con Threads
8
Primo Esempio:
package Prove;
import java.awt.*;
class MyThreadA extends Thread {
public void run() { // entry point for thread!
for (;;) {
System.out.println("hello world1");
}
}
}
class MyThreadB extends Thread {
public void run() { // entry point for thread!
for (;;) {
System.out.println("hello world2");
}
}
}
public class Prova1 {
public static void main(String [] args) {
MyThreadA t1 = new MyThreadA();
MyThreadB t2 = new MyThreadB();
t1.start();
t2.start();
// main terminates, but in Java the other threads keep running!
// and hence Java program continues running!
}
}
Una volta attivati con il metodo start() i due TH verranno elaborati casualmente.
yield()
Esempio 2
package Prove;
import java.awt.*;
class EsThread extends Thread {
private String nome;
public EsThread(String nome){
this.nome = nome;
}
public void run() { // entry point for thread!
for (;;) {
System.out.println("hello" + nome);
yield();
}
}
}
public class Prova2 {
public static void main(String [] args) {
EsThread t1 = new EsThread("aaaaa");
EsThread t2 = new EsThread("KKKKKK");
t1.start();
t2.start();
// main terminates, but in Java the other threads keep running!
// and hence Java program continues running!
Guido Massa Finoli Programmazione Java con Threads
9
}
}
helloaaaaa
helloKKKKKK
helloaaaaa
helloKKKKKK
helloaaaaa
helloKKKKKK
helloaaaaa
helloKKKKKK
helloaaaaa
helloKKKKKK
helloaaaaa
In questo caso invece il metodo yield() , determina il passaggio del Th che ha yield() allo stato
runnable, permettendo in tal modo lesecuzione dellaltro Th, ma non detto che il TH che lo
sostituisce nello stato run non sia lo stesso.
join()
package Prove;
import java.lang.Math;
class MathSin extends Thread {
public double deg;
public double res;
public MathSin(int degree) {
deg = degree;
}
public void run() {
System.out.println("Gradi " + deg);
double Deg2Rad = Math.toRadians(deg);
res = Math.sin(Deg2Rad);
System.out.println("Seno = "+res);
}
}
class MathCos extends Thread {
public double deg;
public double res;
public MathCos(int degree) {
deg = degree;
}
public void run() {
System.out.println("Gradi "+deg);
double Deg2Rad = Math.toRadians(deg);
res = Math.cos(Deg2Rad);
System.out.println("Coseno "+res);
}
}
class MathTan extends Thread {
public double deg;
public double res;
public MathTan(int degree) {
deg = degree;
}
public void run() {
System.out.println("Gradi "+deg);
double Deg2Rad = Math.toRadians(deg);
res = Math.tan(Deg2Rad);
System.out.println("Tangente "+res);
}
Guido Massa Finoli Programmazione Java con Threads
10
}
class Prova3 {
public static void main(String args[]) {
MathSin st = new MathSin(45);
MathCos ct = new MathCos(60);
MathTan tt = new MathTan(30);
st.start();
ct.start();
tt.start();
try { // wait for completion of all thread and then sum
st.join();
ct.join(); //wait for completion of MathCos object
tt.join();
double z = st.res + ct.res + tt.res;
System.out.println("Somma di seno, coseno e tangente "+z);
}
catch(InterruptedException IntExp) {
}
}
}
Gradi 60.0
Gradi 30.0
Gradi 45.0
Tangente 0.5773502691896257
Seno = 0.7071067811865475
Coseno 0.5000000000000001
Somma di seno, coseno e tangente 1.7844570503761732
In questo caso lutilizzo del metodo join() permette di avere il calcolo indipendente e casuale
nellordine del seno , del coseno e della tangente ma ogni TH una volta eseguito si mette in uno
stato di bloccato fino a quando tutti i TH sono eseguiti e bloccati e il sistema ritorna al TH
principale.
setPriority()
Lesecuzione con priorit permette di assegnare una priorit di esecuzione al TH attraverso la
funzione setPriority() , la priorit pu andare da 1 a 10con i valori generalizzati:
MIN_PRIORITY = 1, NORM_PRIORITY = 5, MAX_PRIORITY = 10
package Prove;
/* ThreadPriorityDemo.java: A program which shows altering order of threads
by changing priority. */
class A extends Thread {
public void run() {
System.out.println("Inizio TH A");
for(int i = 1; i <= 4; i++) {
System.out.println("\t From ThreadA: i= " + i);
}
System.out.println("Fine A");
}
}
class B extends Thread {
public void run() {
System.out.println("Inizio TH B");
for(int j = 1; j <= 4; j++) {
System.out.println("\t From ThreadB: j= " + j);
}
System.out.println("Fine B");
}
Guido Massa Finoli Programmazione Java con Threads
11
}
class C extends Thread {
public void run() {
System.out.println("Inizio TH C");
for(int k = 1; k <= 4; k++) {
System.out.println("\t From ThreadC: k= " + k);
}
System.out.println("Fine C");
}
}
public class Prova4 {
public static void main(String args[]) {
A threadA = new A();
B threadB = new B();
C threadC = new C();
threadC.setPriority(Thread.MAX_PRIORITY);
threadB.setPriority(threadA.getPriority() + 1);
threadA.setPriority(Thread.MIN_PRIORITY);
System.out.println("Inizio TH A"+ threadA.getPriority());
threadA.start();
System.out.println("Inizio TH B"+ threadB.getPriority());
threadB.start();
System.out.println("Inizio TH C"+ threadC.getPriority());
threadC.start();
System.out.println("Fine TH main");
}
}
Inizio TH A5
Inizio TH B6
Inizio TH A
From ThreadA: i= 1
From ThreadA: i= 2
From ThreadA: i= 3
From ThreadA: i= 4
Fine A
Inizio TH C10
Inizio TH C
From ThreadC: k= 1
From ThreadC: k= 2
From ThreadC: k= 3
From ThreadC: k= 4
Fine C
Fine TH main
Inizio TH B
From ThreadB: j= 1
From ThreadB: j= 2
From ThreadB: j= 3
From ThreadB: j= 4
Fine B
Occorre notare come il TH iniziale pu essere C, B e anche A. In definitva il TH da cui iniziare non
detto che sia quello con la priorit massima.
interrupt()
Un thread pu essere interrotto invocando su di esso il metodo interrupt(); tale metodo rappresenta
per solo una segnalazione per il thread che lo riceve:
a) se il thread stava lavorando, continuer a farlo
b) se il thread stava in wait(), viene sollevata uneccezione
Guido Massa Finoli Programmazione Java con Threads
12
c) se il thread era bloccato su unoperazione di I/O.Su alcuni sistemi si potrebbe ottenere
leccezione, ma generalmente il thread resta bloccato e interrupt non ha effetto
Guido Massa Finoli Programmazione Java con Threads
13
4) Schedulazione dei Threads
Lesecuzione di thread multipli su una singola CPU, in qualche ordine, detto scheduling.
Il Java runtime supporta un semplice algoritmo di scheduling deterministico conosciuto come fixed
priority scheduling, che schedula i threads sulla base delle loro priorit relative agli altri runnable
threads. Quando un thread viene creato esso eredita la sua priorita dal thread che lo ha creato
possibile modificare la priorit di un thread in qualsiasi momento dopo la sua creazione
utilizzando il metodo setPriority() Le priorit dei Thread sono interi compresi fra
MIN_PRIORITY e MAX_PRIORITY (constanti definite nelle classe Thread); il valore intero pi
grande corrisponde alla pi alta priorit
Ad un dato istante, quando pi thread sono pronti per essere eseguiti, il runtime system sceglie il
thread runnable con la pi alta priorit per lesecuzione. Solo quando il thread finisce o diventa not
runnable per qualche ragione il thread di priorita minore viene eseguito
Il thread scelto sar eseguito fino a quando:
1) un thread con pi alta priorit non diventa runnable.
2) il suo metodo run esiste.
3) su un sistema con time-slicing, il suo slice terminato
Ad ogni istante il thread di massima priorit dovrebbe essere in esecuzione. Comunque, ci non
garantito.
Inoltre, un dato thread pu in un qualsiasi momento cedere i suoi diritti di esecuzione invocando il
metodo yield; la cessione vale solo per thread con la stessa priorit.
Thread possiede anche metodi deprecated : stop(), ma preferibile terminare il thread quando
termina il metodo run()
suspend() e resume(), che possono provocare deadlock
Guido Massa Finoli Programmazione Java con Threads
14
5) Sincronizzazione dei Threads
Uno dei problemi nella gestione dei TH quello del loro controllo quando utilizzano risorse
condivise. La soluzione prospettata in java quella del Monitor o Box, per cui un solo TH pu
accedere ad un Box e rimanere in esso fino a quando non viene completato.
Esempi di risorse condivise sono:
1) Il Problema di Lettura/Scrittura
2) Il Problema Produttore/Consumatore
Il problema lettura/scrittura si ha quando pi TH cercano di accedere ad una stessa risorsa per
leggere e per scrivere, evidente che in tal caso va messo un semaforo che permetta ad un TH di
non soppiantare un altro fino a quando esso non abbia finito loperazione.
Questo reso possibile dalla parola chiave synchronized che va messo come specifica del metodo
del TH override di run().
Nellesempio sotto pu essere notata la differenza tra una call(..) non sicronizzata e una call(..)
sincronizzata. Nel primo caso si ha uno scenario race per cui molto probabile che immesso un TH
esso venga interrotto prima del completamento per fare posto agli altri successivi. Mentre con
lopzione synchronized il TH in start() non viene sostituito prima che sia completato.
Esempio
package Prove;
/* Programma sincronizzato */
class CallMe {
synchronized void call(String msg) {
System.out.print("[" + msg);
try{
Thread.sleep(1000);
} catch(InterruptedException e ){
System.out.println("Interrotto");
}
System.out.println("]");
}
}
class Caller implements Runnable {
String msg;
CallMe target;
Thread t;
public Caller(CallMe targ, String s) {
target = targ;
msg = s;
t = new Thread(this);
t.start();
}
public void run() {
target.call(msg);
}
}
class Prova5 {
public static void main(String args[]) {
CallMe target = new CallMe();
Caller ob1 = new Caller(target, "Ciao");
Caller ob2 = new Caller(target, "Sincronizzato");
Caller ob3 = new Caller(target, "Mondo");
try{
Guido Massa Finoli Programmazione Java con Threads
15
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch(InterruptedException e){
System.out.println("Interrotto");
}
}
}
[Ciao]
[Mondo]
[Sincronizzato]
Come si vede viene scelta lopzione estensione di Runnable per creare il Thread e passare
alloverride run(). Viene creata prima una istanza della classe CallMe che contiene il metodo call(),
poi 3 istanze della classe Caller estensione di Runnable a cui viene passata listanza di CallMe e il
messaggio. Quando viene creata lestanza di Caller viene creato anche il TH associato e viene fatto
partire, con loverride su run() che chiama dallistanza CallMe passata il metodo call() con il
messaggio.
ob1.t.start();
ob2.t.start();
ob3.t.start();
System.out.println("S "+ ob1.t.getState()+ " " +
ob2.t.getState() + " " + ob3.t.getState());
ob1.t.run();
System.out.println("S "+ ob1.t.getState()+ " " +
ob2.t.getState() + " " + ob3.t.getState());
ob3.t.run();
ob1.t.run();
System.out.println("S "+ ob1.t.getState()+ " " +
ob2.t.getState() + " " + ob3.t.getState());
Se proviamo a gestire dal main i TH e controllando lo stato dei TH nel caso sincronizzato, avremo
una possibile situazione del genere:
S RUNNABLE RUNNABLE RUNNABLE
[Ciao]
[MondoS BLOCKED BLOCKED TIMED_WAITING
]
[Sincronizzato]
[Ciao]
[Mondo]
S TERMINATED TERMINATED TERMINATED
Ovvero ogni TH termina il metodo call(), BLOCCANDO gli altri, e rimanendo in WAITING
quando il suo ciclo contiene un sleep() come nel caso di call(). Se invece poniamo il metodo call()
NON sincronizzato allora avremo una esecuzione race, con vari possibili scenari, ad esempio:
[Ciao[SincronizzatoS TIMED_WAITING TIMED_WAITING RUNNABLE
[Ciao[Mondo]
]
]
S TERMINATED TERMINATED TIMED_WAITING
[Mondo]
Guido Massa Finoli Programmazione Java con Threads
16
]
S TERMINATED TERMINATED TERMINATED
Come si vede in questo caso il TH1 quando andato di sleep() ha permesso lentrata in esecuizione
del TH2, che a sua volta andato in sleep() ha rimandato il controllo al main permettendo la scrittura
dello stato. IL TH che riparte non tra quelli in coda o il TH3 ma un nuovo TH1 attivato con
run(), poi viene eseguito il TH3 e poi di nuovo il TH3.
Se proviamo a rilanciarlo pi volte vediamo come lo scenario cambia in continuazione:
S RUNNABLE RUNNABLE RUNNABLE
[Mondo[Sincronizzato[Ciao[Ciao]
]
]
]
S TERMINATED TERMINATED TERMINATED
S TERMINATED TERMINATED TERMINATED
[Ciao[Sincronizzato[MondoS RUNNABLE TIMED_WAITING TIMED_WAITING
[Ciao]
]
]
]
S TERMINATED TERMINATED TERMINATED
S TERMINATED TERMINATED TERMINATED
Proviamo adesso a indicare una situazione nella quale il TH ha un ciclo infinito
Guido Massa Finoli Programmazione Java con Threads
17
6) Esempio tipico, problema produttore/consumatore:
Una applicazione Java ha un thread (produttore) che scrive dati su un file mentre un secondo thread
(consumatore) legge i dati dallo stesso file. Digitando caratteri sulla tastiera il thread produttore
pone levento key in una coda di eventi e il thread consumatore consumer legge gli eventi dalla
stessa coda. Ambedue questi esempi coinvolgono thread concorrenti che condividono una risorsa
comune (File e coda di eventi), pertanto i thread devono essere sincronizzati.
Lattivit di Producer e Consumer pu essere sincronizzata con due strumenti:
A) I due thread non devono accedere simultaneamente alloggetto Box, quindi serve un lock
B) I due thread devono coordinarsi. Il Producer deve indicare al Consumer che il valore pronto e il
Consumer deve avere un modo per notificare che il valore stato prelevato. La classe Thread ha
una collezione di metodi (wait, notify, e notifyAll) che consentono ai threads di aspettare una
condizione e notificare ad altri threads che la condizione cambiata.
Il lock serve per regolare laccesso alla risorsa condivisa; il lock tuttavia non garantisce nessun
ordine nelle operazioni, ma solo il mutex, per questo serve anche il coordinamento Il segmento di
codice entro un programma che accede ad un oggetto da diversi threads concorrenti chiamato
regione critica.
Le regioni critiche possono essere un blocco di istruzioni o un metodo e sono identificate dalla
keyword synchronized():
Posta prima delle istruzioni in accordo alla sintassi synchronized (expr) { <istruzioni> }, dove expr
un riferimento alloggetto che sar locato oppure nella dichiarazione del metodo (public int
synchronized metodo).
La prima scelta potrebbe essere la migliore, perch raffina il livello di granularit, riducendo
lacquisizione del lock solo alle istruzioni strettamente necessarie, ed inoltre la prima scelta
permette di effettuare la sincronizzazione anche su oggetti diversi da this, specificandoli nella expr.
Il metodo, daltra parte, potrebbe essere una buona scelta progettuale per localizzarvi tutto il codice
Sincronizzato. Java associa un lock ad ogni oggetto che ha del codice synchronized. I lock sono
acquisiti per thread, quindi se un metodo sincronizzato chiama un altro metodo sincronizzato, non si
cerca di ottenere altri lock; in tal modo, possibile effettuare chiamate anche ricorsive, e/o di
metodi ereditati senza incorrere in blocchi o deadlock perch il lock acquisito resta sempre uno solo
In ogni momento possibile sapere se un oggetto lockato da un thread invocando dal codice di
tale thread il metodo statico holdslock della classe thread, che come parametro accetta
loggetto e restituisce un booleano che indica lacquisizione del lock. Quando una classe estesa
opera loverriding di un metodo sincronizzato, pu anche non imporre la sincronizzazione nel
metodo sovrascrivente; esso risulter per automaticamente sincronizzato se invoca super
P = Operazione Produttore C = Operazione Consumatore
1) Ogni prodotto immesso deve essere consumato
2) Un prodotto immesso NON pu essere consumato 2 volte
Guido Massa Finoli Programmazione Java con Threads
18
Per rendere questo meccanismo pi facilmente comprensibile creiamo un Th produttore che chiama
un metodo put2(), di una classe Coda2 con oggetto comune, esso si occupa di aggiungere 1 ad una
variabile condivisa, inoltre laggiornamento avverr solo quando il semaforo a false, altrimenti in
esso si attiver un loop che terr il Th bloccato su quella risorsa. Lo stesso avverr per il metodo
get2(), dove si avr valore 1, e il loop attivo a true.
Se la variabile D = true il ciclo P sar il loop, ma siccome i due Th creati sono concorrenti ogni tanto uno
uscir dal loop per timeslice, e sar eseguito laltro ciclo che trovando la variabile D a true eseguir la parte
successiva del codice C_ESEC e metter D a false, ora se il loop fosse eseguito solo dal controllo di D, il
loop P non sarebbe eseguito e di conseguenza sarebbe eseguito il codice P_ESEC. Quindi con un semplice
True False
P C
P_ESEC
D = true
C_ESEC
D = false
Guido Massa Finoli Programmazione Java con Threads
19
loop di controllo della variabile semaforo D, e con soli 2 Th attivi uno consumatore e uno produttore vi sono
buone possibilit che il sistema esegua sempre P e C alternativamente.
Ma se proviamo a mettere nel ciclo while del loop gestito dalla variabile D un ciclo annidato fatto da un
contatore fino ad esempio 30, vedremo che accadr una cosa molto singolare. Che quando il ciclo va in
timeslice in P con D = true viene eseguito C_ESEC messo D a false, ma quando rientra P esso ancora nel
ciclo for di P malgrado D = false, e quindi P_ESEC non verr eseguito, ma al nuovo timeslice verr eseguito
di nuovo C_ESEC. Se poniamo un valore 1 che indica se il ciclo in P, e -1 se in C, possiamo monitorare
chiaramente il processo che avviene nel sistema.
public static void main(String [] args) {
Coda2 co = new Coda2();
Produttore pro = new Produttore(co);
Consumatore con = new Consumatore(co);
pro.start();
con.start();
}
private int valore;
private boolean disponibile = false;
private long count = 0;
public int get2() {
while (disponibile == false){
for(int i=0; i <= 30; i++){
count = - 1;
if (i >= 30) {
disponibile = false;
}
}
}
valore = valore - 1;
disponibile = false;
System.out.print("Get __# "+ valore + " c "+ count + " " + disponibile);
count = 0;
return valore;
}
public int put2() {
while (disponibile == true){
for(int i=0; i<= 30; i++){
count = + 1;
if (i >= 30) {
disponibile = true;
}
}
}
valore = valore + 1;
disponibile = true;
System.out.print("Put __# "+ valore+ " c " + count + " " + disponibile);
count = 0;
return valore;
}
}
Put __# 1 c 0 true Produttore __# 1
Get __# 0 c 1 false Consumatore __# 0
Put __# 1 c -1 true Produttore __# 1
Put __# 2 c -1 true Produttore __# 2
Put __# 3 c -1 true Produttore __# 3
Guido Massa Finoli Programmazione Java con Threads
20
Put __# 4 c -1 true Produttore __# 4
Put __# 5 c -1 true Produttore __# 5
(come si vede il ciclo get rimasto nel for infatti il valore count -1, ma il
semaforo su true in quanto il Th uscito dal ciclo for per timeslice, e
questo ha permesso al ciclo put di eseguire direttamente la procedura P_ESEC che
incrementa il contatore e mette il semaforo a true. Ma malgrado il valore del
semaforo sia a true quando ritorna al ciclo get non viene effettuato le
istruzione C_ESEC in quanto il Th si trova ancora nel ciclo for).
Get __# 4 c 1 false Consumatore __# 4
Get __# 3 c 1 false Consumatore __# 3
Get __# 2 c 1 false Consumatore __# 2
Put __# 3 c -1 true Produttore __# 3
Get __# 2 c 1 false Consumatore __# 2
Get __# 1 c 0 false Consumatore __# 1
Get __# 0 c 1 false Consumatore __# 0
Get __# -1 c 1 false Consumatore __# -1
Put __# 0 c -1 true Produttore __# 0
Get __# -1 c 1 false Consumatore __# -1
Put __# 0 c -1 true Produttore __# 0
Put __# 1 c -1 true Produttore __# 1
Get __# 0 c 1 false Consumatore __# 0
Put __# 1 c -1 true Produttore __# 1
Put __# 2 c -1 true Produttore __# 2
Put __# 3 c -1 true Produttore __# 3
Put __# 4 c -1 true Produttore __# 4
Put __# 5 c -1 true Produttore __# 5
Get __# 4 c 1 false Consumatore __# 4
Get __# 3 c 1 false Consumatore __# 3
Put __# 4 c -1 true Produttore __# 4
Put __# 5 c -1 true Produttore __# 5
Put __# 6 c -1 true Produttore __# 6
Put __# 7 c -1 true Produttore __# 7
Get __# 6 c 1 false Consumatore __# 6
Get __# 5 c 1 false Consumatore __# 5
Get __# 4 c 1 false Consumatore __# 4
Get __# 3 c 1 false Consumatore __# 3
Get __# 2 c 1 false Consumatore __# 2
Get __# 1 c 1 false Consumatore __# 1
Put __# 2 c -1 true Produttore __# 2
Put __# 3 c -1 true Produttore __# 3
Put __# 4 c -1 true Produttore __# 4
Put __# 5 c -1 true Produttore __# 5
Put __# 6 c -1 true Produttore __# 6
Get __# 5 c 1 false Consumatore __# 5
Put __# 6 c -1 true Produttore __# 6
Get __# 5 c 1 false Consumatore __# 5
Get __# 4 c 1 false Consumatore __# 4
Get __# 3 c 1 false Consumatore __# 3
Get __# 2 c 1 false Consumatore __# 2
Get __# 1 c 1 false Consumatore __# 1
Put __# 2 c -1 true Produttore __# 2
Put __# 3 c -1 true Produttore __# 3
Put __# 4 c -1 true Produttore __# 4
Put __# 5 c -1 true Produttore __# 5
Get __# 4 c 1 false Consumatore __# 4
Get __# 3 c 1 false Consumatore __# 3
Get __# 2 c 1 false Consumatore __# 2
Get __# 1 c 1 false Consumatore __# 1
Get __# 0 c 1 false Consumatore __# 0
Get __# -1 c 1 false Consumatore __# -1
Get __# -2 c 1 false Consumatore __# -2
Put __# -1 c -1 true Produttore __# -1
Get __# -2 c 1 false Consumatore __# -2
Guido Massa Finoli Programmazione Java con Threads
21
Put __# -1 c -1 true Produttore __# -1
Get __# -2 c 1 false Consumatore __# -2
Put __# -1 c -1 true Produttore __# -1
Put __# 0 c -1 true Produttore __# 0
Get __# -1 c 1 false Consumatore __# -1
Get __# -2 c 1 false Consumatore __# -2
Put __# -1 c -1 true Produttore __# -1
Put __# 0 c -1 true Produttore __# 0
Put __# 1 c -1 true Produttore __# 1
Put __# 2 c -1 true Produttore __# 2
Put __# 3 c -1 true Produttore __# 3
Put __# 4 c -1 true Produttore __# 4
Get __# 3 c 1 false Consumatore __# 3
Get __# 2 c 1 false Consumatore __# 2
Get __# 1 c 1 false Consumatore __# 1
Put __# 2 c -1 true Produttore __# 2
Get __# 1 c 1 false Consumatore __# 1
Cosa accade se sincronizziamo i 2 metodi put() e get()?
Accadr che i 2 Th lavoreranno in alternativa sulloggetto coda, e questo comporter che get e put
saranno sempre alternati.
public static void main(String [] args) {
Coda2 co = new Coda2();
Produttore pro = new Produttore(co);
Consumatore con = new Consumatore(co);
pro.start();
con.start();
}
private int valore;
private boolean disponibile = false;
private long count = 0;
public synchronized int get2() {
while (disponibile == false){
for(int i=0; i <= 3; i++){
count = - 1;
if (i >= 3) {
disponibile = false; }
}
try {
wait();
}catch (InterruptedException e){
}
}
valore = valore - 1;
disponibile = false;
System.out.println("Get __# "+ valore + " c "+ count + " " + disponibile);
count = 0;
notifyAll();
return valore;
}
Guido Massa Finoli Programmazione Java con Threads
22
public synchronized int put2() {
while (disponibile == true){
for(int i=0; i<= 3; i++){
count = + 1;
if (i >= 3) {
disponibile = true; }
}
try {
wait();
}catch (InterruptedException e){
}
}
valore = valore + 1;
disponibile = true;
System.out.println("Put __# "+ valore+ " c " + count + " " + disponibile);
count = 0;
notifyAll();
return valore;
}
}
Put __# 1 c -1 true
Get __# 0 c 0 false
Consumatore __# 0
Produttore __# 1
Put __# 1 c -1 true
Get __# 0 c 0 false
Consumatore __# 0
Produttore __# 1
Put __# 1 c -1 true
Get __# 0 c 0 false
Consumatore __# 0
Produttore __# 1
Put __# 1 c -1 true
Get __# 0 c 0 false
Consumatore __# 0
Produttore __# 1
Put __# 1 c -1 true
Produttore __# 1
Get __# 0 c 1 false
Put __# 1 c 0 true
Produttore __# 1
Consumatore __# 0
Get __# 0 c 1 false
Put __# 1 c 0 true
Produttore __# 1
Consumatore __# 0
Get __# 0 c 1 false
Put __# 1 c 0 true
Produttore __# 1
Consumatore __# 0
Get __# 0 c 1 false
Put __# 1 c 0 true
Produttore __# 1
Consumatore __# 0
Get __# 0 c 1 false
Put __# 1 c 0 true
Produttore __# 1
Consumatore __# 0
Get __# 0 c 1 false
Consumatore __# 0
Put __# 1 c -1 true
Guido Massa Finoli Programmazione Java con Threads
23
Get __# 0 c 0 false
Consumatore __# 0
Produttore __# 1
Put __# 1 c -1 true
Get __# 0 c 0 false
Consumatore __# 0
Produttore __# 1
Put __# 1 c -1 true
Get __# 0 c 0 false
Consumatore __# 0
Produttore __# 1
Put __# 1 c -1 true
Get __# 0 c 0 false
Consumatore __# 0
Produttore __# 1
Put __# 1 c -1 true
Get __# 0 c 0 false
Consumatore __# 0
Produttore __# 1
Put __# 1 c -1 true
Produttore __# 1
Get __# 0 c 1 false
Put __# 1 c 0 true
Produttore __# 1
Consumatore __# 0
Get __# 0 c 1 false
Per evitare anomalie di questo tipo si trasformano put() e get() in metodi sincronizzati, ovvero si
crea un Monitor e si utilizzano i metodi : wait(), notifyAll() , notify()
Il monitor permette di aggiungere alla definizione di tipo di dati astratto una specifica della
sincronizzazionefra i threads per mezzo dellinvocazione dei seguenti metodi:
- wait(): tale metodo rilascia il lock (mutua esclusione) sull'oggetto e sospende il thread che lo
invoca in attesa di una notifica.
- notifyAll(): tale metodo risveglia tutti i thread sospesi sull'oggetto in attesa di notifica. I thread
risvegliati competono per acquisire il lock (mutua esclusione) sull'oggetto.
- notify(): tale metodo risveglia un thread scelto casualmente tra quelli sospesi sull'oggetto in
attesa di notifica. Il thread risvegliato compete per acquisire il lock (mutua esclusione) sull'oggetto.
I metodi wait(), notify() e notifyAll() devono essere invocati dall'interno di un metodo o blocco
sincronizzato.
Quindi nel nostro esempio le classi Produttore e Consumatoore rimangono identiche mentre
cambiano i metodi get() e put().
Guido Massa Finoli Programmazione Java con Threads
24
7) Particolarit dei Threads
a) Caso
class MyThread extends Thread
{
MyThread() {}
MyThread(Runnable r) {super(r); }
public void run()
{
System.out.print("Inside Thread ");
}
}
class MyRunnable implements Runnable
{
public void run()
{
System.out.print(" Inside Runnable");
}
}
class ProveG
{
public static void main(String[] args)
{
new MyThread().start();
new MyThread(new MyRunnable()).start();
}
}
Inside Thread Inside Thread
In questo caso viene creato un primo oggetto MyThread invocando il costruttore
MyThread(), una volta creato loggetto con lo start() si attiva il metodo run()
che scrive Inside Thread. Nel secondo caso viene invocato il secondo
costruttore che ha come paramentro un oggetto Runnable che viene creato al
momento, il metodo nel costruttore invoca la runnable della superclasse ma essa
non vine mai utilizzata in quanto al momento dello start() si attiva sempre il
run() del Thread. Infatti il codice equivalente al:
class MyThread extends Thread
{
MyThread() {}
MyThread(Runnable r) {}
public void run()
{
System.out.print("Inside Thread ");
}
}
class MyRunnable implements Runnable
{
public void run()
{
System.out.print(" Inside Runnable");
}
}
class ProveG
{
public static void main(String[] args)
{
new MyThread().start();
new MyThread(new MyRunnable()).start();
Guido Massa Finoli Programmazione Java con Threads
25
}
}
b) Caso : esempio NON sincronizzato
class ProveG2 implements Runnable
{
int x, y;
public void run()
{
for(int i = 0; i < 10; i++)
{
x = 12 - i;
y = 12 + i;
System.out.println(x + " " + y + " ");
try {
Thread.sleep(100);
} catch(InterruptedException e){
System.out.println("Interrotto");
}
}
System.out.println(" Fine ");
}
public static void main(String args[])
{
ProveG2 run = new ProveG2();
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
t1.start();
t2.start();
}
}
12 12
12 12
11 13
11 13
10 14
10 14
9 15
9 15
8 16
8 16
7 17
7 17
6 18
6 18
5 19
5 19
4 20
4 20
3 21
3 21
Fine
Fine
Guido Massa Finoli Programmazione Java con Threads
26
c) Caso : esempio intero metodo run() sincronizzato
class ProveG2 implements Runnable
{
int x, y;
public synchronized void run()
{
for(int i = 0; i < 10; i++)
{
x = 12 - i;
y = 12 + i;
System.out.println(x + " " + y + " ");
try {
Thread.sleep(100);
} catch(InterruptedException e){
System.out.println("Interrotto");
}
}
System.out.println(" Fine ");
}
public static void main(String args[])
{
ProveG2 run = new ProveG2();
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
t1.start();
t2.start();
}
}
12 12
11 13
10 14
9 15
8 16
7 17
6 18
5 19
4 20
3 21
Fine
12 12
11 13
10 14
9 15
8 16
7 17
6 18
5 19
4 20
3 21
Fine
Guido Massa Finoli Programmazione Java con Threads
27
d) Caso : sincronizzazione del blocco
La semplice sincronizzazione del blocco non comporta alcun cambiamento rispetto
al primo esempio, in quanto il blocco del ciclo for() viene eseguito una sola
volta e poi rilasciato.
class ProveG2 implements Runnable
{
int x, y;
public void run()
{
for(int i = 0; i < 10; i++)
synchronized(this)
{
x = 12 - i;
y = 12 + i;
System.out.println(x + " " + y + " ");
try {
Thread.sleep(100);
} catch(InterruptedException e){
System.out.println("Interrotto");
}
}
System.out.println(" Fine ");
}
12 12
12 12
11 13
11 13
10 14
9 15
8 16
7 17
10 14
9 15
8 16
7 17
6 18
5 19
4 20
3 21
Fine
6 18
5 19
4 20
3 21
Fine
Guido Massa Finoli Programmazione Java con Threads
28
8) Esempio di Automa Cellulare utilizzando Threads
A) Caso
Classe AC_Ricorsive utilizza una ricorsiva ciclica per settare a 1 le cellule di una struttura cellulare
30 x 30.
Classe StatoCellule reperisce lo stato di una cellula ( che pu essere 0 o 1) e lo modifica sulla base
dei valori delle 4 cellule adiacenti.
Classe Thread definisce un ciclo infinito che dai valori delle 4 cellule adiacenti cambia quello della
cellula di riferimento modificandone il colore a seconda che sia 0 o 1.
Definizione di un Applet
che crea tutti gli oggetti necessari e attiva un thread corrispondente ad ogni cellula.
/* Classe per definire una ricorsiva meromorfa passate le coordinate del punto
dinnesco e il numero di cicli determinanti il corrispondente numero di cellule
e loro coordinate caricate in schiere */
public class AC_Ricorsive {
double valx[], valy[];
public int valIx[], valIy[];
int px1, px2, py1, py2;
public double x_max, x_min;
public int ass_x_max, ass_x_min;
int ass_y_max, ass_y_min;
double y_max, y_min;
int n_ind;
public double coeff_x, coeff_y;
public AC_Ricorsive(int x1, int x2, int y1, int y2, int h){
valx = new double[h];
valIx = new int[h];
valy = new double[h];
valIy = new int[h];
px1 = x1;
px2 = x2;
py1 = y1;
py2 = y2;
x_max = 0;
ChiamaCell
StatoCellula
ThreadCellula
AC_Ricorsive
Crea
oggetti
Attivazione
Guido Massa Finoli Programmazione Java con Threads
29
x_min = 1000;
y_max = 0;
y_min = 1000;
n_ind = h;
}
public void Calco_1(double c1, double c2, double c3, double c4) {
valx[0]= c1;
valx[1]= c2;
valy[0]=c3;
valy[1]=c4;
valIx[0]= (int) valx[0];
valIx[1]= (int) valx[1];
valIy[0]= (int) valy[0];
valIy[1]= (int) valy[1];
int k;
for(k = 2 ; k<n_ind; k++){
double d1 = valx[k-1]*valx[k-2] - valy[k-1]*valy[k-2];
double d2 = valx[k-2]*valy[k-1] + valy[k-2]*valx[k-1];
double h1 = d1*d1;
double h2 = d2*d2;
valx[k] = (px1*d1*(valx[k-1]+1)+px2*d2*valy[k-1])/(h1+h2);
valy[k] = (py1*d1*(valy[k-1])+py2*d2*(valx[k-1]+1))/(h1+h2);
valIx[k] = (int) valx[k];
valIy[k] = (int) valy[k];
if (valx[k]>x_max) x_max = valx[k];
if (valx[k]<x_min) x_min = valx[k];
if (valy[k]>y_max) y_max = valy[k];
if (valy[k]<y_min) y_min = valy[k];
}
ass_x_min =Math.abs((int) x_min);
ass_x_max =Math.abs((int) x_max);
coeff_x =50.00/(ass_x_min + ass_x_max);
ass_y_min =Math.abs((int) y_min);
ass_y_max =Math.abs((int) y_max);
coeff_y =50.00/(ass_y_min + ass_y_max);
for(k = 2 ; k<n_ind; k++){
valIx[k] = (int) ((Math.abs(valIx[k])+ass_x_min)*coeff_x);
valIy[k] = (int) ((Math.abs(valIy[k])+ass_y_min)*coeff_y);
}
}
}
/* Classe che definisce lo stato di una singola cellula
* individuata dalle sue coordinate
* Il costruttore setta lo stato indiziale
* Metodo InquiryCell interroga lo stato
* Metodo ModStato modifica lo stato
*/
public class StatoCellule {
int CBx, CBy; /* coordinate */
int SCBi; /* stato iniziale */
int SCBf; /* stato finale */
StatoCellule(int x, int y){
Guido Massa Finoli Programmazione Java con Threads
30
CBx = x;
CBy = y;
SCBi = 0;
SCBf = 1;
}
StatoCellule(int x, int y, int Si){
CBx = x;
CBy = y;
SCBi = Si;
SCBf = 9;
}
StatoCellule(int x, int y, int Si, int Sf){
CBx = x;
CBy = y;
SCBi = Si;
SCBf = Sf;
}
public synchronized int InquiryCell(int x, int y, char St){
if(St == 'i')return SCBi;
else return SCBf;
}
public synchronized int InquiryCell(char St){
if(St == 'i')return SCBi;
else return SCBf;
}
public synchronized void ModStato(int x0, int x1, int x2,int x3, int x4){
int M0, M1, M2, M3, M4;
int CCS0, CCST;
M0 = x0;
M1 = x1;
M2 = x2;
M3 = x3;
M4 = x4;
CCST = M1 + M2 + M3 + M4;
/* Se le 4 celle intorno alla cellula di rif sono a stato 1 */
/* Allora stato finale a 0 */
if(CCST==4) {SCBf = 0;
}
/* Se le 3 celle intorno alla cellula di rif sono a stato 1 */
/* Allora stato finale a 1*/
if(CCST==3) SCBf = 1;
/* Se le 2 celle intorno alla cellula di rif sono a stato 1 */
/* Allora stato finale a 0*/
if(CCST==2) SCBf = 0;
/* Se le 1 celle intorno alla cellula di rif sono a stato 1 */
/* Allora stato finale a 0*/
if(CCST==1) SCBf = 1;
/* Se 0 celle intorno alla cellula di rif sono a stato 1 */
/* Allora stato finale a 0*/
if (CCST==0) SCBf = 0;
SCBi = SCBf;
}
}
Guido Massa Finoli Programmazione Java con Threads
31
/* Thread di attivazione delle cellula
* Passati 4 riferimenti delle cellule intorno a quella di riferimento
* Passato il bottone, e le coordinate della cellula di riferimento
* Il ciclo run modifica lo stato della cellulla di rif sulla base di quello
* delle altre 4 cellule
* e cambia il colore del bottone di rif. */
public class ThreadCellule extends Thread {
int CBx, CBy; /* coordinate */
int m, q; /* stato iniziale */
int SCBi, SCBf; /* stato finale */
StatoCellule op0, op1, op2, op3, op4;
int ACS0, ACS1, ACS2, ACS3, ACS4;
Button ok;
long l;
public ThreadCellule(StatoCellule pp0,StatoCellule pp1,StatoCellule pp2,
StatoCellule pp3,StatoCellule pp4,Button kk, int x , int y){
CBx = x;
CBy = y;
op0 = pp0;
op1 = pp1;
op2 = pp2;
op3 = pp3;
op4 = pp4;
ok = kk;
}
public void run(){
long q = 200;
for(; ;){
ACS0 = op0.InquiryCell('i');
ACS1 = op1.InquiryCell('i');
ACS2 = op2.InquiryCell('i');
ACS3 = op3.InquiryCell('i');
ACS4 = op4.InquiryCell('i');
op0.ModStato(ACS0, ACS1, ACS2, ACS3, ACS4);
System.out.println("S " +ACS0 + " " + CBx + CBy + " " + ACS1 + ACS2
+ ACS3 + ACS4);
ok.setLabel(" " + ACS0);
if(ACS0 == 0){
ok.setBackground(Color.green);
}
if(ACS0 == 1){
ok.setBackground(Color.blue);
}
try {
Thread.sleep(q);
} catch(InterruptedException e){
System.out.println("Interrotto");
}
}
}
}
/*
<applet code="MatriceNumerica" width=600 height=400>
</applet>
Guido Massa Finoli Programmazione Java con Threads
32
*/
/* 1) creazione bottoni in schiera bidimensionale
* 2) creazione cellula in schiera bidimensionale
* 3) creazione thread in schiera bidimensionale
*/
public class ChiamaCell extends Applet{
public static final int n = 31;
static int ind = 0;
Button bList[][] = new Button[n][n];
int Col1[][] = new int[n][n];
StatoCellule nome[][] = new StatoCellule[n][n];
StatoCellule pp0,pp1,pp2,pp3,pp4;
ThreadCellule TH[][] = new ThreadCellule[n][n];
public void init(){
AC_Ricorsive Eseguiric = new AC_Ricorsive(-1, 1, 1, 1, 8100);
Eseguiric.Calco_1(50, 166, 100, 100);
for (int q = 1; q<8000; q++){
if((Eseguiric.valIx[q] <(n-1)) & (Eseguiric.valIy[q]<(n-1))){
Col1[Eseguiric.valIy[q]][Eseguiric.valIx[q]]=1;}
}
for (int i = 1; i < n; i++){
for (int j = 1; j < n; j++){
if(Col1[i][j]==1){
nome[i][j] = (StatoCellule) new StatoCellule(i, j, 1);}
else
nome[i][j] = (StatoCellule) new StatoCellule(i, j, 0);
Col1[i][j] = nome[i][j].InquiryCell(i, j, 'i');
}
}
setLayout(new GridLayout(n,n));
setFont(new Font("Helvetica", Font.BOLD, 12));
resize(1000,800);
for(int i = 1; i < n; i++){
for(int j= 1; j < n; j++){
int k = Col1[i][j];
bList[i][j] = (Button) add(new Button(" " + k));
if(k == 0)
bList[i][j].setBackground(Color.white);
if(k== 1)
bList[i][j].setBackground(Color.yellow);
}
}
}
/* bottone premuto e attivazione Thread*/
public boolean keyDown(Event evtObj, int key){
if(key ==evtObj.F5){
for(int i = 1; i<n;i++){
for(int j=1; j<n;j++){
pp0 = nome[i][j];
int Mx = i -1;
if(Mx<1)Mx= n-1;
int My = j;
Guido Massa Finoli Programmazione Java con Threads
33
pp1 = nome[Mx][My];
My = j -1;
if(My<1)My= n-1;
Mx = i;
pp2 = nome[Mx][My];
Mx = i +1;
if(Mx>n-1)Mx= 1;
My = j;
pp3 = nome[Mx][My];
My = j +1;
if(My> n-1)My= 1;
Mx = i;
pp4 = nome[Mx][My];
TH[i][j] = (ThreadCellule2) new ThreadCellule2(pp0, pp1,
pp2, pp3, pp4, bList[i][j],i, j);
TH[i][j].start();
}
}
return true;
}
return false;
}
public void stop(){
}
public void destroy(){
}
}
Guido Massa Finoli Programmazione Java con Threads
34
Guido Massa Finoli Programmazione Java con Threads
35
B) Caso
In questo caso viene definito anche uno stato del sistema che controlla il numero di celle con stato
attivo (= 1)unato
Stato Sistema
public class StatoSistema {
int num; /* Numero di elementi attivi */
public static int del;
private boolean F = false;
private int tot;
StatoSistema(int att){
num = att;
del = 55;
}
public synchronized int CallTH(int s0, int som){
int val = s0;
tot = som;
if(del >= num) {
if (s0 == 1) {
del = del - 1;
val = 0;}
System.out.println("Usc Magg. " + del );
} else if (del <=0){
if (s0 == 0) {
del = del + 1;
val = 1;}
System.out.println("Usc Minore " + del );
} else {
if ( tot == 4 ){
ChiamaCell2
StatoCellula2
ThreadCellula2
AC_Ricorsive
Crea
oggetti
Attivazione
yield()
StatoSistema
Guido Massa Finoli Programmazione Java con Threads
36
if (s0 == 1) {
del = del - 1;
val = 0;
System.out.println(" --1 " + del );
}
}
else if (tot == 2 || tot == 3){
if (s0 == 0) {
del = del + 1;
val = 1;
System.out.println(" + 1 " + del );
}
}
else if (tot == 0 | tot == 1){
val = s0;
}
}
return val;
}
}
StatoCellula2 chiama StatoSistema per cambiare o meno lo stato della cellula:
public class StatoCellule2 {
int CBx, CBy; /* coordinate */
int SCBi; /* stato iniziale */
int SCBf; /* stato finale */
StatoSistema SS;
StatoCellule2(int x, int y, StatoSistema sis){
CBx = x;
CBy = y;
SCBi = 0;
SCBf = 1;
SS = sis;
}
StatoCellule2(int x, int y, int Si, StatoSistema sis){
CBx = x;
CBy = y;
SCBi = Si;
SCBf = 9;
SS = sis;
}
StatoCellule2(int x, int y, int Si, int Sf, StatoSistema sis){
CBx = x;
CBy = y;
SCBi = Si;
SCBf = Sf;
SS = sis;
}
public synchronized int InquiryCell(int x, int y, char St){
if(St == 'i')return SCBi;
else return SCBf;
}
Guido Massa Finoli Programmazione Java con Threads
37
public synchronized int InquiryCell(char St){
if(St == 'i')return SCBi;
else return SCBf;
}
public synchronized void ModStato(int x0, int x1, int x2,int x3, int x4){
int M0, M1, M2, M3, M4;
int CCS0, CCST;
M0 = x0;
M1 = x1;
M2 = x2;
M3 = x3;
M4 = x4;
CCST = M1 + M2 + M3 + M4;
/*System.out.println("I " +M0 + " " + M1 + M2 + M3 + M4);*/
/* Se le 4 celle intorno alla cellula di rif sono a stato 1 */
/* Allora stato finale a 0 */
if(CCST==4) {SCBf = SS.CallTH(M0, CCST);
}
/* Se le 3 celle intorno alla cellula di rif sono a stato 1 */
/*
if(CCST==3) SCBf = SS.CallTH(M0, CCST);
/* Se le 2 celle intorno alla cellula di rif sono a stato 1 */
/*
if(CCST==2) SCBf = SS.CallTH(M0, CCST);
/* Se le 1 celle intorno alla cellula di rif sono a stato 1 */
/*
if(CCST==1) SCBf = SS.CallTH(M0, CCST);
/* Se 0 celle intorno alla cellula di rif sono a stato 1 */
/*
if (CCST==0) SCBf = SS.CallTH(M0, CCST);
SCBi = SCBf;
}
}
Il Thread viene eseguito in un unico blocco sincronizzato ed inoltre viene invocato il metodo yield()
per permettere agli altri Th runnable di passare a stato di run()
public class ThreadCellule2 extends Thread {
int CBx, CBy; /* coordinate */
int m, q; /* stato iniziale */
int SCBi, SCBf; /* stato finale */
StatoCellule2 op0, op1, op2, op3, op4;
int ACS0, ACS1, ACS2, ACS3, ACS4, ACSW;
Button ok;
long l;
public ThreadCellule2(StatoCellule2 pp0,StatoCellule2 pp1,StatoCellule2
pp2,
StatoCellule2 pp3,StatoCellule2 pp4,Button kk, int x , int y){
CBx = x;
CBy = y;
op0 = pp0;
op1 = pp1;
op2 = pp2;
op3 = pp3;
op4 = pp4;
Guido Massa Finoli Programmazione Java con Threads
38
ok = kk;
}
public void run(){
long q = 150;
for(; ;){
synchronized (this){
ACS0 = op0.InquiryCell('i');
ACSW = ACS0;
ACS1 = op1.InquiryCell('i');
ACS2 = op2.InquiryCell('i');
ACS3 = op3.InquiryCell('i');
ACS4 = op4.InquiryCell('i');
System.out.println("S_IN " +ACS0 + " " + CBx + " " + CBy + " " +
ACS1 + ACS2 + ACS3 + ACS4);
op0.ModStato(ACS0, ACS1, ACS2, ACS3, ACS4);
ACS0 = op0.InquiryCell('i');
ok.setLabel(" " + StatoSistema.del);
if(ACS0 == 0){
ok.setBackground(Color.green);
}
if(ACS0 == 1){
ok.setBackground(Color.blue);
}
System.out.println("S_OUT " +ACS0 + " " + CBx + " " + CBy + " " +
ACS1 + ACS2 + ACS3 + ACS4);
}
yield();
}
}
}
ChiamaCellule2 e AC_Ricorsive rimangono allo stesso modo della precedente versione.
Guido Massa Finoli Programmazione Java con Threads
39
Guido Massa Finoli Programmazione Java con Threads
40
Gruppi di Threads : Threads Deamon e User
Ogni thread Java un membro di un thread group. Il Thread group fornisce un meccanismo per
collezionare pi thread in un singolo oggetto e manipolare questi threads tutti insieme piuttosto che
individualmente
I Java thread groups sono implementati dalla classe java.lang.ThreadGroup.
Il runtime system pone un thread in un thread group durante la sua costruzione. Quando viene
creato un thread, si pu permettere al runtime system di porlo in un default group o si pu
esplicitamente selezionare il gruppo desiderato. Il thread un membro permanente del gruppo in cui
inserito allatto della creazione; non quindi possibile spostare un thread in un nuovo gruppo
dopo la sua creazione.
Se vengono generati solo thread daemon, opzione NON di default, lapplicazione termina quando
termina il primo thread di partenza (quello che esegue il main); in quel momento, anche tutti i
thread demoni sono stoppati. Se si desidera questo comportamento, devono quindi essere marcati
esplicitamente come demoni tutti i thread generati
Se esiste invece almeno un thread utente, lapplicazione non termina con il thread del main, ma
solo quando tutti i thread utente saranno terminati; al completamento dellultimo thread utente,
anche tutti gli eventuali thread demoni saranno arrestati e lapplicazione potr avere fine
I thread utente sono quindi dotati di maggiore indipendenza rispetto ai demoni, e permettono ad
unapplicazione di avere una vita pi lunga rispetto al thread del solo main. Questa situazione
potrebbe in alcuni casi non essere desiderabile; esiste sempre la possibilit di invocare il metodo
exit di System.
Thread main
ThreadGroup
GR
Threads
Daemon =
termina con in
main
User = prosegue
autonomamente
Guido Massa Finoli Programmazione Java con Threads
41
9) Simulazione sistema automatico di produzione
Videata_1 = Crea
oggetti e attiva TH
ChiamaFrame =
JFrame x bottoni e
videata
Java.swing
Java.awt
Thread CS
TH inizio
Coda
Oggetti
A
Oggetti
B
Magazzino
Mb
Magazzino
Ma
MagazzinoScambio
Thread SK TH Fine
Creazione
altri
oggetti
come CS
Guido Massa Finoli Programmazione Java con Threads
42
Main
public class Videata_1
{
public static int sTCS = 2000, sTSK = 1000, sMAP = 100;
public static int sMAC = 300, sMAS = 200;
public static int b2 = 41, b1 = 11;
public static Coda DD;
public static void main(String args[])
{
DD = new Coda();
ChiamaFrame pp = new ChiamaFrame();
ThreadGroup GRCS = new ThreadGroup("OggCS");
ThreadGroup GRSK = new ThreadGroup("OggSK");
/* Creo 1 Oggetto Magazzino */
MagScambio Maga = new MagScambio();
Magazzino Ma = new Magazzino();
Magazzino Mb = new Magazzino();
/* Creo 3 oggetti della Classe_A */
Classe_A A1 = new Classe_A(Ma);
Classe_A A2 = new Classe_A(Ma);
Classe_A A3 = new Classe_A(Ma);
/* Creo 3 oggetti della Classe_B */
Classe_B B1 = new Classe_B(Mb);
Classe_B B2 = new Classe_B(Mb);
/* Creo 10 Thread */
ThreadCS TH[] = new ThreadCS[b2];
ThreadSK TK[] = new ThreadSK[b1];
JButton BO[] = new JButton[7];
/* for (int i=1; i<11;i++){
TH[i].start();
System.out.println("Immesso " + i);
}*/
pp.A1.setBackground(Color.GREEN);
pp.A1.setText("A1 " + "POS " + 10+ " NEG " + 1 );
pp.A2.setBackground(Color.GREEN);
pp.A2.setText("A2 " + "POS " + 10+ " NEG " + 1 );
pp.A3.setBackground(Color.GREEN);
pp.A3.setText("A3 " + "POS " + 10+ " NEG " + 1 );
pp.B1.setBackground(Color.ORANGE);
pp.B1.setText("B1 " + "VAL " + 10);
pp.B2.setBackground(Color.orange);
pp.B2.setText("B2 " + "VAL " + 10);
pp.MA.setBackground(Color.MAGENTA);
pp.MA.setText("MA " + "VAL " + 0);
BO[1] = pp.A1;
BO[2] = pp.A2;
BO[3] = pp.A3;
BO[4] = pp.B1;
BO[5] = pp.B2;
BO[6] = pp.MA;
for (int i=1; i<b2;i++){
Guido Massa Finoli Programmazione Java con Threads
43
TH[i] = (ThreadCS) new ThreadCS(GRCS, A1,A2,A3,B1,B2, Maga,
pp.N[i], i, BO);
}
for (int i=1; i<b1;i++){
TK[i] = (ThreadSK) new ThreadSK(GRSK, A1,A2,A3,B1,B2, Maga,
pp.Q[i], i, BO);
}
GRCS.setDaemon(true);
GRSK.setDaemon(true);
for (int i=1; i<b2;i++){
TH[i].start();
System.out.println("Immesso " + i);
}
for (int i=1; i<b1;i++){
TK[i].start();
System.out.println("Immesso " + i);
}
}
}
Creazione videata con Jframe e Jbutton
public class ChiamaFrame extends JFrame{
public static int a2 = 41, a1 = 11;
JPanel nord = new JPanel();
JPanel centro = new JPanel();
JPanel sud = new JPanel();
JButton N[] = new JButton[a2];
JButton Q[] = new JButton[a1];
JButton A1 = new JButton("Carico A1");
JButton A2 = new JButton("Carico A2");
JButton A3 = new JButton("Carico A3");
JButton B1 = new JButton("Carico B1");
JButton B2 = new JButton("Carico B2");
JButton MA = new JButton("Maga Scambio");
Ascoltatore listener = new Ascoltatore();
public ChiamaFrame()
{
super("Ciclo_Thread");
for (int h = 1 ; h<a2;h++){
N[h] = (JButton) add(new JButton(" " + h));
N[h].setSize(150, 150);
}
for (int h = 1 ; h<a1;h++){
Q[h] = (JButton) add(new JButton(" " + h));
Q[h].setSize(150, 150);
}
Container c = this.getContentPane();
/*centro.setLayout(new FlowLayout());*/
centro.setLayout(new GridLayout(5,1));
for (int h = 1; h < a2; h++){
centro.add(N[h], CENTER_ALIGNMENT);
}
for (int h = 1; h < a1; h++){
centro.add(Q[h], CENTER_ALIGNMENT);
Guido Massa Finoli Programmazione Java con Threads
44
}
/*nord.setLayout(new FlowLayout());*/
nord.setLayout(new GridLayout(1,2));
nord.add(A1, LEFT_ALIGNMENT);
nord.add(A2, LEFT_ALIGNMENT);
nord.add(A3, LEFT_ALIGNMENT);
sud.setLayout(new GridLayout(1,2));
sud.add(B1, LEFT_ALIGNMENT);
sud.add(B2, LEFT_ALIGNMENT);
sud.add(MA, LEFT_ALIGNMENT);
c.setLayout(new BorderLayout());
c.add(nord, BorderLayout.NORTH);
c.add(centro, BorderLayout.CENTER);
c.add(sud, BorderLayout.SOUTH);
MA.addActionListener(listener);
setSize(1000,700);
setVisible(true);
}
public class Ascoltatore implements ActionListener
{
public void actionPerformed(ActionEvent e){
Object src = e.getSource();
if (src==MA)
{A1.setBackground(Color.BLACK);
}
}
}
Creazione ciclo del TH CS
public class ThreadCS extends Thread {
int m, q, conta;
Classe_A op1, op2, op3;
Classe_B ob1, ob2;
MagScambio MM;
JButton ok;
JButton OB[];
long l;
ThreadInizio ini;
ThreadFine fin;
public ThreadCS(ThreadGroup cs, Classe_A pp1, Classe_A pp2, Classe_A pp3,
Classe_B bb1, Classe_B bb2, MagScambio MA, JButton kk , int u,
JButton BB[]){
q = u;
conta = 0;
op1 = pp1;
op2 = pp2;
op3 = pp3;
ob1 = bb1;
ob2 = bb2;
MM = MA;
ok = kk;
m = 1;
Guido Massa Finoli Programmazione Java con Threads
45
OB = BB;
ini = new ThreadInizio(q, false);
fin = new ThreadFine(q, false);
}
public void run(){
m = 1;
for(int k = 1 ; k < 5; k++){
k = k + 1;
if (m == 1){
ini.G = true;
System.out.println("Inizio " + q);
ThreadCS.this.setPriority(8);
}
if (m<10) {m = op1.CaricaA(m, 0);
OB[1].setBackground(Color.WHITE);
OB[1].setText("A1 " + " VAL " + op1.POS + " " + op1.NEG);
ok.setBackground(Color.GREEN);
ok.setText("T" + q + " V " + m);
/*System.out.println("OP1 Carico " + m + " " + q);*/
}
if (m<10) {m = op2.CaricaA(m, 0);
OB[2].setBackground(Color.WHITE);
OB[2].setText("A2 " + " VAL " + op2.POS + " " + op2.NEG);
ok.setBackground(Color.GREEN);
ok.setText("T" + q + " V " + m);
}
if (m<10) {m = op3.CaricaA(m, 0);
OB[3].setBackground(Color.WHITE);
OB[3].setText("A3 " + " VAL " + op3.POS + " " + op3.NEG);
ok.setBackground(Color.GREEN);
ok.setText("T" + q + " V " + m);
}
try {
Thread.sleep(Video.Videata_1.sTCS);
} catch(InterruptedException e){
System.out.println("Interrotto");
}
if (m>= 10){
for(int f=1;f<10;f++){
if (m<300) {m = ob1.CaricaB(m, 0);
OB[4].setBackground(Color.WHITE);
OB[4].setText("B1 " + " VAL " + ob1.BOS );
ok.setBackground(Color.ORANGE);
ok.setText("T" + q + " V " + m);
/*System.out.println("OB1 Carico " + m + " " + q);}*/
}
if (m<500) {m = ob2.CaricaB(m, 0);
OB[5].setBackground(Color.WHITE);
OB[5].setText("B2 " + " VAL " + ob2.BOS );
ok.setBackground(Color.ORANGE);
ok.setText("T" + q + " V " + m);
/*System.out.println("OB2 Carico " + m + " " + q);}*/
/*ok.setBackground(Color.GRAY);
ok.setText("T " + q + " VAL " + m);*/
/*System.out.println("Totale " + m + " " + q);}*/
Guido Massa Finoli Programmazione Java con Threads
46
/*m = 501;*/
}
if (m>499) {
ok.setBackground(Color.BLUE);
ok.setText("F" + q + " V " + m);
System.out.println("Finale " + m + " " + q);
OB[6].setBackground(Color.GRAY);
m = MM.put(m);
OB[6].setText("MA " + " VAL " + MM.QUA);
}
if (m == 0){
fin.G=true;
ThreadCS.this.setPriority(2);
conta = conta + 1;
ok.setBackground(Color.WHITE);
ok.setText("F" + q + " V " + m + " " + conta);
try {
Thread.sleep(Video.Videata_1.sTCS);
} catch(InterruptedException e){
System.out.println("Interrotto");
}
m = 1;
if (k > 5) {
ok.setBackground(Color.BLACK);
ok.setText("F" + q + " V " + m + " " + conta);
}
}
}
}
}
}
}
Creazione ciclo del TH SK (vuoto)
public class ThreadSK extends Thread {
int m, w, q;
Classe_A op1, op2, op3;
Classe_B ob1, ob2;
MagScambio MM;
JButton ok;
JButton OB[];
long l;
public ThreadSK(ThreadGroup sk, Classe_A pp1, Classe_A pp2, Classe_A pp3,
Classe_B bb1, Classe_B bb2, MagScambio MA, JButton kk , int u,
JButton BB[]){
q = u;
op1 = pp1;
op2 = pp2;
Guido Massa Finoli Programmazione Java con Threads
47
op3 = pp3;
ob1 = bb1;
ob2 = bb2;
MM = MA;
ok = kk;
m = 1;
OB = BB;
}
public void run(){
for(;;){
w = MM.get();
m = m + w;
if (m >=5){
ok.setBackground(Color.GRAY);
ok.setText("W" + q + " V " + m);
OB[6].setBackground(Color.GRAY);
OB[6].setText("MA " + " VAL " + MM.QUA);
try {
Thread.sleep(Video.Videata_1.sTSK);
} catch(InterruptedException e){
System.out.println("Interrotto");
}
m = 0;
ok.setBackground(Color.LIGHT_GRAY);
ok.setText("W" + q + " V " + m);
}
}
}
}
TH inizio con put sulla Coda del Thread
public class ThreadInizio extends Thread {
int m, w, q;
boolean G;
long l;
public ThreadInizio(int v, boolean f){
G = f;
q = v;
this.start();
}
public void run(){
for(;;){
if (G == true){
Video.Videata_1.DD.put(q);
G = false;
}
else {
try {
sleep(5);}
catch (InterruptedException e){
}
}
}
}
Guido Massa Finoli Programmazione Java con Threads
48
}
TH fine con get sulla Coda Thread
public class ThreadFine extends Thread {
int m, w, q;
boolean G;
long l;
public ThreadFine(int v, boolean f){
G = f;
q = v;
this.start();
}
public void run(){
for(;;){
if (G == true){
m =Video.Videata_1.DD.get();
G = false;
}
else {
try {
sleep(5);}
catch (InterruptedException e){
}
}
}
}
}
Coda con put e get sincronizzati ed esclusivi
public class Coda {
private int contenuto;
private boolean F = false;
public synchronized int get() {
while(F == false){
try {
wait();
}catch (InterruptedException e){
}
}
F = false;
System.out.println("Fine Thread "+ contenuto);
notifyAll();
return contenuto;
}
public synchronized void put(int valore) {
while(F == true){
try {
wait();
}catch (InterruptedException e){
}
}
Guido Massa Finoli Programmazione Java con Threads
49
contenuto = valore;
System.out.println("Inizio Thread "+ contenuto);
F = true;
notifyAll();
}
}
Oggetti A
public class Classe_A {
boolean F; /* Stato della Classe */
int POS; /* valori positivi */
int NEG;
Magazzino mv;
int za;
public Classe_A(Magazzino pp){
mv = pp;
POS = 10;
NEG = 1;
F = false;
}
public Classe_A(int po, int ne, boolean q){
POS = po;
NEG = ne;
F = q;
}
public int CaricaA(int m, int flag) {
int k, rit, val;
rit = 0;
val = 0;
if(F==false){
F = true;
k = POS - NEG;
if (k > 0){
m = m +k;
NEG = NEG + k;
}
else {
/* reperisco valore da magazzino e lo carico su POS */
F = true;
za = 3;
rit = mv.Preleva_Deposito(za);
rit = rit - 10;
m = 10;
POS = POS + rit;
}
}
F = false;
val = m;
return val;
}
}
Guido Massa Finoli Programmazione Java con Threads
50
Oggetti B
public class Classe_B {
boolean F; /* Stato della Classe */
int BOS; /* valori positivi */
Magazzino mb;
int za;
public Classe_B(Magazzino pp){
mb = pp;
BOS = 10;
F = false;
}
public int CaricaB(int m, int flag) {
int rit, val;
val = 0;
rit = 0;
if(flag == 0){
if(F==false){
F = true;
if (BOS > 100){
m = 100 + m;
BOS = BOS - 100;
}
else {
/* reperisco valore da magazzino e lo carico su POS */
int za = 10;
rit = mb.Preleva_Deposito(za);
BOS = 100 * rit;
BOS = BOS - 100;
m = m + 100;
}}
F = false;
val = m;
}
else if(flag == 1){
if(F==false){
F = true;
rit = mb.Carica_Deposito(m);}
F = false;
val = rit;
}
return val;
}
}
Magazzino degli Oggetti A e B
public class Magazzino {
boolean F; /* Stato della Classe */
int DEP; /* valori positivi */
int k;
public Magazzino(){
Guido Massa Finoli Programmazione Java con Threads
51
DEP = 3000;
}
public synchronized int Preleva_Deposito(int z){
for(int g = 2; g <z ; g++){
k = g*10;
try {
wait(Video.Videata_1.sMAP);
} catch(InterruptedException e){
System.out.println("Caricamento da Deposito - Interrotto");
}
}
DEP = DEP - k;
return k;
}
public synchronized int Carica_Deposito(int val){
int zx;
zx = (int) val/2;
DEP = DEP + zx;
try {
wait(Video.Videata_1.sMAC);
} catch(InterruptedException e){
System.out.println("Caricamento da Deposito -
Interrotto");
}
return zx;
}
}
Magazzino di scambio degli oggetti prodotti da THCS e ricevuti da THSK
public class MagScambio {
boolean F; /* Stato della Classe */
int QUA; /* valori positivi */
int za;
public MagScambio(){
QUA = 0;
F = false;
}
public synchronized int put(int va){
int k, rit;
rit = va;
if (F==false){
F = true;
QUA = QUA + 1;
try {
Thread.sleep(Video.Videata_1.sMAS);
} catch(InterruptedException e){
System.out.println("Interrotto");
}
rit = 0;
}
F = false;
Guido Massa Finoli Programmazione Java con Threads
52
return rit;
}
public synchronized int get(){
int k, car;
car = 0;
if (F==false){
F = true;
if (QUA > 0) {
car = 1;
QUA = QUA - car;
try {
Thread.sleep(Video.Videata_1.sMAS);
} catch(InterruptedException e){
System.out.println("Interrotto");
}
}
}
F = false;
return car;
}
}
Guido Massa Finoli Programmazione Java con Threads
53
Lordine delle azioni di un thread determinato dallordine delle istruzioni del programma cos
come sono scritte dal programmatore (ordine del programma) _ invece i valori di una qualsiasi
variabile letta dal thread sono determinati dal modello della memoria, la cui effettiva
implementazione definisce linsieme di valori ammissibili che possono essere restituiti al momento
della lettura (richiesta con una qualche istruzione presente allinterno del thread)
Solitamente, ci si aspetta che questo insieme di valori ammissibili sia ad ogni istante costituito da
un solo valore, coincidente con il valore pi recente scritto nella variabile da leggere da un qualche
thread che ha operato su di essa; in realt il modello della memoria pu anche operare
differentemente, rendendo invisibile il valore pi recente
Lutilizzo di variabili volatili sostituisce raramente operazioni sincronizzate perch non fornisce
atomicit per azioni diverse dalla semplice lettura; luso quindi limitato.
Il modello della memoria pu influenzare anche lordine di esecuzione delle istruzioni; in genere
esso tenta di garantire lapproccio happens-before, ossia unistruzione che nellordine del
programma scritta prima di unaltra, si verificher prima di questa, come il programmatore
desidererebbe; potrebbe tuttavia anche aversi un ordine effettivo di esecuzione differente
dallordine del programma, a patto che al thread di esecuzione dello stesso leffetto appaia come se
venisse rispettato lordine del programma; questo eventuale cambiamento dellordine effettivo
permette compilatori con ottimizzazioni sofisticate, e il pi delle volte pu essere ignorato dal
programmatore
Corrispondenza
ordine del
programma e
valori della
memoria
Synchronized di
blocco o metodo
Volatile di variabile
= Ultimo valore
aggiornato
Guido Massa Finoli Programmazione Java con Threads
54

You might also like