Dans ce scénario, nous devons développer deux threads qui impriment alternativement les nombres de 1 à 100, l'un dédié aux nombres impairs et l'autre aux nombres pairs. Plusieurs techniques de synchronisation sont applicables, comme les mécanismes wait/notify ou les sémaphores.
Approche avec synchronized et wait/notify
Une classe AlternatingPrinter est définie pour gérer l'impression. Elle utilise un verou pour coordonner l'exécution des threads.
public class AlternatingPrinter {
private final int upperLimit;
private int currentNumber = 1;
private final Object mutex = new Object();
public AlternatingPrinter(int upperLimit) {
this.upperLimit = upperLimit;
}
public void printOdd() {
generateOutput(true);
}
public void printEven() {
generateOutput(false);
}
private void generateOutput(boolean isOddThread) {
for (int step = 0; step < upperLimit / 2; step++) {
synchronized (mutex) {
while (isOddThread == (currentNumber % 2 == 0)) {
try {
mutex.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
System.out.println(Thread.currentThread().getName() + " : " + currentNumber++);
mutex.notify();
}
}
}
}
Ensuite, les threads sont créés et démarrés pour imprimer les nombres impairs et pairs.
AlternatingPrinter printer = new AlternatingPrinter(100);
Thread oddThread = new Thread(printer::printOdd, "Impair");
Thread evenThread = new Thread(printer::printEven, "Pair");
oddThread.start();
evenThread.start();
La sortie résultante respecte l'alternance :
Impair : 1
Pair : 2
Impair : 3
Pair : 4
...
Impair : 99
Pair : 100
Approche avec Sémaphores
Une implémentation alternative utilise des sémaphores pour contrôler l'accès. Chaque thread gère un sémaphore pour signaler le suivant.
public class AlternatingPrinter {
private final int limit;
private int count = 1;
private final Semaphore oddSemaphore = new Semaphore(1);
private final Semaphore evenSemaphore = new Semaphore(0);
public AlternatingPrinter(int limit) {
this.limit = limit;
}
public void printOdd() {
alternate(oddSemaphore, evenSemaphore);
}
public void printEven() {
alternate(evenSemaphore, oddSemaphore);
}
private void alternate(Semaphore current, Semaphore next) {
for (int i = 0; i < limit / 2; i++) {
try {
current.acquire();
System.out.println(Thread.currentThread().getName() + " : " + count++);
next.release();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
}
Cette méthode assure une exécution séquentielle sans verrou explicite, en utilisant l'état initial des sémaphores pour démarrer avec le thread impair.