Java Syncronized: Come si usa esempio

Java Syncronized: Cos’è

Ad ogni oggetto (o anche ad un pezzo di codice) si può associare un semaforo (un lock). Ogni semaforo ha due operazioni: Get e Release. Quando un thread accede ad una zona critica tenta di prendere possesso del semaforo (Get); se non ci riesce verrà messo a dormire e ci ritenterà fino a quando un altro thread rilascerà (Release) tale semaforo.
Questi “semafori” in java vengono introdotti con la parola chiave “syncronized“. Si possono sincronizzare sia classi che metodi.
Quando un thread vuole accedere ad un metodo/blocco synchronized, deve acquisire il lock dell’oggetto (impedendo così l’accesso ad ogni altro thread).  Il lock viene automaticamente rilasciato quando il thread esce dal metodo/blocco synchronized(o se viene interrotto da un’eccezione).
Un thread che non riesce ad acquisire un lock rimane sospeso sulla richiesta della risorsa fino a che il lock non è disponibile. Ad ogni oggetto viene assegnato un solo lock: due thread non possono accedere contemporaneamente a due metodi/blocchi synchronized diversi di uno stesso oggetto.Tuttavia altri thread sono liberi di accedere a metodi/blocchi non synchronized associati allo stesso oggetto.

Java Syncronized: Esempio

ContatoreCondiviso.java

public class ContatoreCondiviso {
public void stampaCont() {

 for(int i = 5; i > 0; i--) {
System.out.println("count --- " + i );
}

}
}

La classe  ContatoreCondiviso sarà usata all’interno del thread del tipo  ThreadDemo.

ThreadDemo.java

public class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ContatoreCondiviso PD;

ThreadDemo( String name, ContatoreCondiviso pd) {
threadName = name;
PD = pd;
}

public void run() {
System.out.println("Starting " + threadName );
PD.stampaCont();
System.out.println("Thread " + threadName + " exiting.");
}
}

Nel main vengono lanciati due thread di tipo ThreadDemo. Notare che entrambi i thread hanno in comune la stessa variabile PD.

main.java

public static void main(String[] args) {</p>
//non sync
ContatoreCondiviso PD = new ContatoreCondiviso();

ThreadDemo T1 = new ThreadDemo("Thread - 1 ", PD);
ThreadDemo T2 = new ThreadDemo("Thread - 2 ", PD);

T1.start();
T2.start();

}

lanciando il main si ottiene:

thread syncronized

Dall’output si nota che il valore della variabile PD (di tipo ContatoreCondiviso), comune ad entrambi i thread, viene cambiata contemporaneamente sia dal thread 1 che dal thread 2.

Aggiungendo la parola chiave syncronized sulla variabile PD:

synchronized (PD) {
PD.stampaCont();
}

garantiamo che solo un thread potrà chiamare il metodo stampaCont(), e se quel thread non ha terminato il metodo nessuno lo potrà richiamare.

Classe thread modificata.

ThreadDemoSync.java

public class ThreadDemoSync extends Thread {
private Thread t;
private String threadName;
ContatoreCondiviso PD;

ThreadDemoSync(String name, ContatoreCondiviso pd) {
threadName = name;
PD = pd;
}

public void run() {
System.out.println("Starting " + threadName);
synchronized (PD) {
PD.stampaCont();
}
System.out.println("Thread " + threadName + " exiting.");
}

}

Main.java

public static void main(String[] args) {</p>
ContatoreCondiviso PD = new ContatoreCondiviso();

ThreadDemoSync T1 = new ThreadDemoSync("Thread - 1 ", PD);
ThreadDemoSync T2 = new ThreadDemoSync("Thread - 2 ", PD);

T1.start();
T2.start();

}

output

thread syncronized

Dall’output si può nota che il thread 2 deve aspettare che il thread 1 finisca elaborazione del metodo stampaCont( quello che stampa i println) per poterlo richiamare.

(Visited 44 times, 1 visits today)

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *