Semaforo
I semafori vengono solitamente utilizzati quando è necessario limitare il numero di thread quando si lavora con il file system. L'accesso a un file o altra risorsa condivisa è controllato tramite un contatore. Se il suo valore è maggiore di zero, l'accesso è consentito, ma allo stesso tempo il contatore diminuirà.
Nel momento in cui il contatore restituisce zero, il thread corrente verrà bloccato fino a quando la risorsa non verrà rilasciata da un altro thread. Il parametro numero di autorizzazioni deve essere impostato tramite il costruttore.
Devi selezionare questo parametro individualmente, a seconda della potenza del tuo computer o laptop.
public class Main {
public static void main(String[] args) {
Semaphore sem = new Semaphore(1);
CommonResource res = new CommonResource();
new Thread(new MyThread(res, sem, "MyThread_1")).start();
new Thread(new MyThread(res, sem, "MyThread_2")).start();
new Thread(new MyThread(res, sem, "MyThread_3")).start();
}
}
class CommonResource {
int value = 0;
}
class MyThread implements Runnable {
CommonResource commonResource;
Semaphore semaphore;
String name;
MyThread(CommonResource commonResource, Semaphore sem, String name) {
this.commonResource = commonResource;
this.semaphore = sem;
this.name = name;
}
public void run() {
try {
System.out.println(name + "waiting permission");
semaphore.acquire();
commonResource.value = 1;
for (int i = 1; i < 7; i++) {
System.out.println(this.name + ": " + commonResource.value);
commonResource.value++;
Thread.sleep(150);
}
} catch (InterruptedException e) {
System.out.println(e.getMessage() + " " + name);
Thread.currentThread().interrupt();
}
System.out.println(name + "releases permission");
semaphore.release();
}
}
CountDownLatch e altri
CountDownLatch : consente a più thread di attendere fino al completamento di un determinato numero di operazioni eseguite su altri thread. Un esempio è l'installazione di un'applicazione: essa non si avvierà finché non si accettano le condizioni d'uso, finché non si seleziona una cartella dove installare un nuovo programma e così via. Esiste uno speciale metodo countDown() per questo : questo metodo decrementa il contatore del conto alla rovescia di uno.
Non appena il conteggio va a zero, tutti i thread in attesa in await continueranno il loro lavoro e tutte le successive chiamate di await passeranno senza attendere. Il contatore del conto alla rovescia è un contatore una tantum e non può essere azzerato.
CyclicBarrier : utilizzato per sincronizzare un determinato numero di thread in un punto. La barriera viene raggiunta quando N thread chiamano il metodo await(...) e bloccano. Successivamente, il contatore viene ripristinato al suo valore originale e i thread in attesa verranno rilasciati. Inoltre, se necessario, è possibile eseguire codice personalizzato prima di sbloccare i thread e reimpostare il contatore. Per fare ciò, un oggetto con un'implementazione dell'interfaccia Runnable viene passato attraverso il costruttore .
Exchanger<V> : la classe Exchanger è destinata allo scambio di dati tra thread. Viene digitato e digita il tipo di dati che i thread devono scambiare.
I dati vengono scambiati utilizzando l'unico metodo exchange() di questa classe :
V exchange(V x) throws InterruptedException
V exchange(V x, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException
Il parametro x rappresenta il buffer di dati da scambiare. La seconda forma del metodo definisce anche il parametro timeout , il timeout e unit , il tipo di unità di tempo da utilizzare per il parametro timeout .
La classe Phaser consente di sincronizzare i thread che rappresentano una singola fase o fase nell'esecuzione di un'azione complessiva. Phaser definisce un oggetto di sincronizzazione che attende il completamento di una determinata fase. Il Phaser passa quindi alla fase o fase successiva e attende che venga completata di nuovo.
Quando si lavora con la classe Phaser , è comune creare prima il suo oggetto. Successivamente, dobbiamo registrare tutti i partecipanti. Per registrarsi per ogni partecipante, viene chiamato il metodo register() , oppure è possibile fare a meno di questo metodo passando il numero richiesto di partecipanti al costruttore Phaser .
Quindi ogni partecipante esegue un certo insieme di azioni che compongono la fase. E il sincronizzatore Phaser attende che tutti i partecipanti abbiano completato l'esecuzione della fase. Per informare il sincronizzatore che la fase è terminata, il partecipante deve chiamare il metodo arrive() o arriveAndAwaitAdvance() . Il sincronizzatore passa quindi alla fase successiva.
GO TO FULL VERSION