CountDownLatch
CountDownLatch permet à un ou plusieusr threads d'attendre la fin d'un ensemble d'opérations dans d'autres threads. Lors de la création, une valeur de comptage est spécifiée. L'appel à await() bloque le thread jusqu'à ce que le comptage atteigne zéro, ce qui se produit chaque fois que countDown() est invoqué, décrémentant ainsi le compteur. Une fois à zéro, tous les threads en attente sont libérés.
public class ExempleCompteur {
public static void main(String[] args) throws InterruptedException {
int nbTaches = 5;
CountDownLatch verrou = new CountDownLatch(nbTaches);
for (int index = 0; index < nbTaches; index++) {
new Thread(() -> {
System.out.println("Thread " + Thread.currentThread().getId() + " a effectué son travail");
verrou.countDown();
}).start();
}
verrou.await();
System.out.println("Toutes les tâches sont complétées.");
}
}
Résultat attendu :
Thread 10 a effectué son travail
Thread 11 a effectué son travail
Thread 12 a effectué son travail
Thread 13 a effectué son travail
Thread 14 a effectué son travail
Toutes les tâches sont complétées.
CyclicBarrier
CyclicBarrier synchronise un groupe de threads de sorte qu'ils attendent tous d'atteindre un point de barrière commun. Contrairement à CountDownLatch, cette barrière est cyclique et peut être réutilisée après libération des threads. Un constructeur permet de spécifier une action à exécuter lorsque tous les threads ont atteint la barrière.
public class ExempleBarriere {
public static void main(String[] args) {
int nombreParticipants = 5;
CyclicBarrier barriere = new CyclicBarrier(nombreParticipants, () -> {
System.out.println("La barrière a été franchie par " + nombreParticipants + " threads.");
});
for (int idx = 0; idx < nombreParticipants; idx++) {
new Thread(() -> {
System.out.println("Thread " + Thread.currentThread().getId() + " arrive à la barrière.");
try {
barriere.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
Résultat attendu :
Thread 10 arrive à la barrière.
Thread 11 arrive à la barrière.
Thread 12 arrive à la barrière.
Thread 13 arrive à la barrière.
Thread 14 arrive à la barrière.
La barrière a été franchie par 5 threads.
Semaphore
Un sémaphore à comptage contrôle l'accès à une ressource en limitant le nombre de threads simultenés. Il maintient un ensemble de permis : acquire() bloque le thread jusqu'à ce qu'un permis soit disponible, tandis que release() libère un permis, permettant à d'autres threads de procéder.
public class ExempleSemaphore {
public static void main(String[] args) {
int maxAccesConcurrents = 3;
Semaphore semaphore = new Semaphore(maxAccesConcurrents);
for (int i = 1; i <= 10; i++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getId() + " accède à la ressource.");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getId() + " libère la ressource.");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}).start();
}
}
}
Résultat attendu :
10 accède à la ressource.
11 accède à la ressource.
12 accède à la ressource.
11 libère la ressource.
10 libère la ressource.
12 libère la ressource.
13 accède à la ressource.
...