Università degli Studi della Calabria
Corso di Laurea in Ingegneria Informatica
Lucidi delle esercitazioni di
Sistemi di Elaborazione in Rete
A.A. 2003/2004
1
Lettori-Scrittori con sincronizzazione Java (1)
public class Database {
private int readerCount;
private boolean dbReading;
private boolean dbWriting;
public Database() {
readerCount = 0;
dbReading = false;
dbWriting = false;
}
public synchronized int startRead() { /* lucidi seguenti */ }
public synchronized int endRead() { /* lucidi seguenti */ }
public synchronized void startWrite() { /* lucidi seguenti */ }
public synchronized void endWrite() { /* lucidi seguenti */ }
}
2
Lettori-Scrittori con sincronizzazione Java (2)
public synchronized int startRead()
{
while (dbWriting == true) {
try {
wait();
}
catch (InterruptedException e) { }
}
readerCount++;
if (readerCount == 1)
dbReading = true;
return readerCount;
}
3
Lettori-Scrittori con sincronizzazione Java (3)
public synchronized int endRead()
{
readerCount- -;
if (readerCount == 0)
{
dbReading=false;
notifyAll();
}
return readerCount;
}
4
Lettori-Scrittori con sincronizzazione Java (4)
public synchronized void startWrite()
{
while (dbReading == true || dbWriting == true) {
try { wait(); }
catch (InterruptedException e) { }
}
dbWriting = true;
}
public synchronized void endWrite()
{
dbWriting = false;
notifyAll();
}
5
Lettori-Scrittori con sincronizzazione Java (5)
public class Readers extends Thread {
Database db;
int id;
public Readers(Database db,int id){
this.db=db;
this.id=id;
}
public void run(){
while (true){
db.startRead();
db.endRead();
}
}
}
6
Lettori-Scrittori con sincronizzazione Java (6)
public class Writers extends Thread {
Database db;
int id;
public Writers(Database db,int id){
this.db=db;
this.id=id;
}
public void run(){
while (true){
db.startWrite();
db.endWrite();
}
}
}
7
Lettori-Scrittori con sincronizzazione Java (7)
public class TestRW {
public static void main(String [ ] args){
Database db=new Database();
for (int i=0;i<10;i++){
(new Readers(db,i)).start();
(new Writers(db,i)).start();
}
}
8
Blocchi sincronizzati (1)
 Anche blocchi di codice, oltre che interi metodi, possono essere
dichiarati synchronized.
 Ciò consente di associare un lock la cui durata è tipicamente inferiore
a quella di un intero metodo synchronized.
9
Blocchi sincronizzati (2)
public void syncronized F() {
// sezione non critica (p.es.: inizializzazione di variabili locali)
// sezione critica
// sezione non critica
}
public void F() {
// sezione non critica
synchronized (this) {
// sezione critica
}
// sezione non critica
}
10
I 5 filosofi con sincronizzazione Java (1)
Supponiamo esista un tavolo con 5 piatti, 5 posti a tavola, 5
forchette ed al centro un’insalatiera di spaghetti. I filosofi seduti
intorno al tavolo sanno fare solo due cose: mangiare e pensare. Il
problema è che, siccome si tratta di spaghetti, il generico filosofo
per servirsi ha bisogno di entrambe le forchette (quella alla sua DS
e quella alla sua SN). Poi per mangare gliene serve solo una.
2
1
1
2
0
0
3
3
4
4
La forchetta a SN dell’i-simo filosofo è: i;
La forchetta a DS dell’i-sima filosofo è: (i+1)%5;
11
I 5 filosofi con sincronizzazione Java (2)
(senza deadlock)
Public class 5Filosofi {
private boolean fork[ ]={true,true,true,true,true};
public synchronized void getForks(int i) {
while(!fork[i] || !fork[(i+1)%5])
try{wait();
}catch(InterruptedException e){ }
fork[i]=false;
fork[(i+1)%5]=false;
notifyAll(); /*eventuale*/
}
public synchronized void putForks(int i) {
fork[i]=true;
fork[(i+1)%5]=true;
notifyAll();
}
}
12
I 5 filosofi con sincronizzazione Java (3)
(senza deadlock e senza starvation)
Public class 5Filosofi {
private boolean fork[ ]={true,true,true,true,true};
int cont[]={0,0,0,0,0};
public synchronized void getForks(int i) {
while(!fork[i] || !fork[(i+1)%5] || (cont[i]>cont[(i+1)%5)] ||
(cont[i]>cont[(i+4)%5])
try{wait();
}catch(InterruptedException e){ }
fork[i]=false;
fork[(i+1)%5]=false;
notifyAll(); /*eventuale*/
}
public synchronized void putForks(int i) {
fork[i]=true;
fork[(i+1)%5]=true;
cont[i]++;
notifyAll();
}
}
13
I 5 filosofi con sincronizzazione Java (4)
(I Threads Filosofo)
public class Filosofo extends Thread {
int id;
5Filosofi cf;
public Filosofo(int id, String nome, 5Filosofi cf) {
super(nome);
this.id=id;
this.cf=cf;
}
public void run() {
for(; ;){
cf.getForks(id);
System.out.println(“Il filosofo”+id+” mangia”);
try{
sleep((int)(Math.random()*5000));
catch(InterruptedException e){ } /*il filosofo sta mangiando*/
cf.putForks(id);
try{
sleep((int)(Math.random()*5000));}
catch(InterruptedException e){ } /*il filosofo sta pensando*/
}
}
}
14
I 5 filosofi con sincronizzazione Java (4)
(Il main)
public class Test5Filosofi {
public static void main(String [] args){
5Filosofi gestore=new 5Filosofi();
for (int i=0;i<5;i++)
new Filosofo(i,”Filosofo# “+i, gestore).start();
}
}
15
Il problema dello Sleeping Barber
E’ dato un salone di barbiere, avente un certo numero di posti d’attesa
ed un’unica poltrona di lavoro. Nel salone lavora un solo barbiere, il
quale è solito addormentarsi sulla poltrona di lavoro in assenza di clienti.
Arrivando nel salone, un cliente può trovare le seguenti situazioni:
• Il barbiere dorme sulla poltrona di lavoro. Il cliente sveglia il barbiere e si
accomoda sulla poltrona di lavoro, quindi il barbiere lo serve.
• Il barbiere sta servendo un altro cliente: se ci sono posti d’attesa liberi, il
cliente attende, altrimenti se ne va.
Scrivere in Java un programma che risolva tale problema, simulando
l’attività dei diversi soggetti (il Salone, il Barbiere, i Clienti) ed
evidenziandone su video lo stato.
L’implementazione della soluzione deve far uso delle opportune primitive
di sincronizzazione e mutua esclusione.
16
Salone (1)
public class Salone implements Runnable {
int sedie,posti;
Thread barbiere=null;
boolean dorme,cliente;
boolean fineAttesa;
public Salone(int sedie){
this.sedie=sedie;
posti=sedie;
dorme=true;
cliente=false;
fineAttesa=false;
barbiere=new Thread(this);
barbiere.start();
}
public synchronized boolean richiesta ( ) { … }
public void run ( ) { … }
}
17
Salone: richiesta (2)
public synchronized boolean richiesta( ) {
if (posti==0) return false;
if ( (posti<sedie) || (!dorme)){
posti--;
while(true) {
try {wait();}catch(InterruptedException e){ }
if (fineAttesa){
fineAttesa=false;
notifyAll();
break;
}
}
cliente=true;
}
else{
dorme=false;
cliente=true;
notify();
}
while (cliente)
try{wait();}catch(InterruptedException e){}
return true;
}
18
Salone: run (3)
public void run ( ) {
while (true){
synchronized(this) {
if (!cliente) {
if (posti==sedie) {
dorme=true;
while(dorme)
try{wait();}catch(InterruptedException e){ }
}
else{posti++;fineAttesa=true;
notify();
while (fineAttesa)
try{wait();}catch(Interrupted…){}
} /*fine synchronized*/
try{ Thread.sleep((int)(Math.random*1000));}catch(…){};
synchronized (this){
cliente=false;
notifyAll();
}
}
}
}/*fine Salone*/
19
Cliente (1)
class Cliente extends Thread {
private Salone salone;
private int id;
public Cliente (Salone salone, int id) {
this.salone = salone;
this.id = id;
}
public void run () {
while (true) {
boolean servito=salone.richiesta();
if (servito) {
int tempoDiRicrescita = (int)((Math.random()*3000));
System.out.println ("Il cliente "+id+" attende la ricrescita dei capelli.
"+"Tempo di ricrescita = "+tempoDiRicrescita);
try {
sleep (tempoDiRicrescita);
} catch (InterruptedException e) { System.out.println (e); }
20
Cliente (2)
else{
System.out.println(“Il cliente+ id+”trova tutto pieno e va via…”);
int tempoDiRiprovo= (int)((Math.random()*1000));
try {
sleep (tempoDiRiprovo);
} catch (InterruptedException e) { System.out.println (e); }
}
} // while
}
}
21
Il problema dello Sleeping Barber
public class SleepingBarber {
public static void main (String args[]) {
int postiDiAttesa=5;
Salone s = new Salone (postiDiAttesa); /*il barbiere è già attivo*/
for (int i = 1; i <= 10; i++) {
Cliente c = new Cliente (s, i);
c.start ();
}
}
}
22