Imprimer les nombres pairs et impairs à l’aide de 2 fils

Imprimer des nombres pairs et impairs à l'aide de 2 fils

1. introduction

Dans ce didacticiel, nous allons voir comment nous pouvons imprimer des nombres pairs et impairs à l'aide de deux threads.

Le but est d’imprimer les nombres dans l’ordre, alors qu’un fil n’imprime que les nombres pairs et que l’autre ne trace que les nombres impairs. Nous utiliserons les concepts de synchronisation des threads et de communication inter-thread pour résoudre le problème.

2. Discussions en Java

Les threads sont des processus légers pouvant être exécutés simultanément. L'exécution simultanée de plusieurs threads peut être bénéfique en termes de performances et d'utilisation du processeur, car nous pouvons travailler sur plusieurs tâches à la fois via différents threads exécutés en parallèle.

Plus d'informations sur les threads en Java peuvent être trouvées dans cearticle.

In Java, we can create a thread by either extending the Thread class or by implementing the Runnable interface. Dans les deux cas, nous remplaçons la méthoderun et y écrivons l'implémentation du thread.

Vous trouverez plus d'informations sur l'utilisation de ces méthodes pour créer un threadhere.

3. Synchronisation de fil

Dans un environnement multithread, il est possible que 2 threads ou plus accèdent à la même ressource à peu près au même moment. Cela peut être fatal et conduire à des résultats erronés. Pour éviter cela, nous devons nous assurer qu'un seul thread accède à la ressource à un moment donné.

Nous pouvons y parvenir en utilisant la synchronisation de threads.

En Java, nous pouvons marquer une méthode ou un bloc comme synchronisé, ce qui signifie qu'un seul thread pourra entrer cette méthode ou ce bloc à un moment donné.

Plus de détails sur la synchronisation des threads en Java peuvent être trouvés surhere.

4. Communication inter-thread

La communication inter-thread permet aux threads synchronisés de communiquer entre eux à l'aide d'un ensemble de méthodes.

Les méthodes utilisées sontwait,notify, etnotifyAll, qui sont toutes héritées de la classeObject.

Wait() causes the current thread to wait indefinitely until some other thread calls notify() or notifyAll() on the same object. Nous pouvons appelernotify() pour réveiller les threads qui attendent d'accéder au moniteur de cet objet.

Plus de détails sur le fonctionnement de ces méthodes peuvent être trouvéshere.

5. Impression de nombres pairs et impairs alternativement

5.1. Utilisation dewait() etnotify()

Nous allons utiliser les concepts discutés de synchronisation et de communication inter-thread pour imprimer des nombres impairs et pairs dans un ordre croissant en utilisant deux threads différents.

In the first step, we’ll implement the Runnable interface to define the logic of both threads. Dans la méthoderun, nous vérifions si le nombre est pair ou impair.

Si le nombre est pair, on appelle la méthodeprintEven de la classePrinter, sinon on appelle la méthodeprintOdd:

class TaskEvenOdd implements Runnable {
    private int max;
    private Printer print;
    private boolean isEvenNumber;

    // standard constructors

    @Override
    public void run() {
        int number = isEvenNumber ? 2 : 1;
        while (number <= max) {
            if (isEvenNumber) {
                print.printEven(number);
            } else {
                print.printOdd(number);
            }
            number += 2;
        }
    }
}

Nous définissons la classePrinter comme suit:

class Printer {
    private volatile boolean isOdd;

    synchronized void printEven(int number) {
        while (!isOdd) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        System.out.println(Thread.currentThread().getName() + ":" + number);
        isOdd = false;
        notify();
    }

    synchronized void printOdd(int number) {
        while (isOdd) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        System.out.println(Thread.currentThread().getName() + ":" + number);
        isOdd = true;
        notify();
    }
}

In the main method, we use the defined class to create two threads. Nous créons un objet de la classePrinter et le passons comme paramètre au constructeurTaskEvenOdd:

public static void main(String... args) {
    Printer print = new Printer();
    Thread t1 = new Thread(new TaskEvenOdd(print, 10, false),"Odd");
    Thread t2 = new Thread(new TaskEvenOdd(print, 10, true),"Even");
    t1.start();
    t2.start();
}

Le premier thread sera le thread impair, donc nous passonsfalse comme valeur du paramètreisEvenNumber. Pour le deuxième thread, nous passonstrue à la place. Nous définissons lesmaxValue sur 10 pour les deux fils, de sorte que seuls les nombres de 1 à 10 soient imprimés.

Nous démarrons ensuite les deux threads en appelant la méthodestart(). Cela invoquera la méthoderun() des deux threads telle que définie ci-dessus dans laquelle nous vérifions si le nombre est impair ou pair et les imprimons.

Lorsque le thread impair commence à s'exécuter, la valeur de la variablenumber sera 1. Comme il est inférieur àmaxValue et que l'indicateurisEvenNumber est faux,printOdd() est appelé. Dans la méthode, nous vérifions si le drapeauisOdd est vrai et s'il est vrai, nous appelonswait().  PuisqueisOdd est faux au départ,wait() n'est pas appelé et la valeur est imprimé.

We then set the value of isOdd to true, so that the odd thread goes into the wait state and call notify() pour réveiller le thread pair. Le thread pair se réveille alors et imprime le nombre pair puisque l'indicateurodd est faux. Il appelle ensuitenotify() pour réveiller le thread impair.

Le même processus est effectué jusqu'à ce que la valeur de la variablenumber soit supérieure aumaxValue.

5.2. Utilisation de sémaphores

Un sémaphore contrôle l'accès à une ressource partagée à l'aide d'un compteur. Si lecounter is greater than zero, then access is allowed. S'il est égal à zéro, l'accès est refusé.

Java fournit la classeSemaphore dans le packagejava.util.concurrent et nous pouvons l'utiliser pour implémenter le mécanisme expliqué. Plus de détails sur les sémaphores peuvent être trouvéshere.

Nous créons deux threads, un thread impair et un thread pair. Le fil impair imprime les nombres impairs à partir de 1 et le fil pair imprime les nombres pairs à partir de 2.

Les deux threads ont un objet de la classeSharedPrinter. The SharedPrinter class will have two semaphores, semOdd and semEven which will have 1 and 0 permits to start with. Cela garantira que le nombre impair est imprimé en premier.

Nous avons deux méthodesprintEvenNum() etprintOddNum().  Le thread impair appelle la méthodeprintOddNum() et le thread pair appelle la méthodeprintEvenNum().

Pour imprimer un nombre impair, la méthodeacquire() est appelée sursemOdd, et comme le permis initial est 1, elle acquiert l'accès avec succès, imprime le nombre impair et appellerelease() sursemEven.

L'appel derelease() incrémentera le permis de 1 poursemEven, et le thread pair peut alors acquérir avec succès l'accès et imprimer le nombre pair.

Voici le code du workflow décrit ci-dessus:

public static void main(String[] args) {
    SharedPrinter sp = new SharedPrinter();
    Thread odd = new Thread(new Odd(sp, 10),"Odd");
    Thread even = new Thread(new Even(sp, 10),"Even");
    odd.start();
    even.start();
}
class SharedPrinter {

    private Semaphore semEven = new Semaphore(0);
    private Semaphore semOdd = new Semaphore(1);

    void printEvenNum(int num) {
        try {
            semEven.acquire();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println(Thread.currentThread().getName() + num);
        semOdd.release();
    }

    void printOddNum(int num) {
        try {
            semOdd.acquire();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println(Thread.currentThread().getName() + num);
        semEven.release();

    }
}

class Even implements Runnable {
    private SharedPrinter sp;
    private int max;

    // standard constructor

    @Override
    public void run() {
        for (int i = 2; i <= max; i = i + 2) {
            sp.printEvenNum(i);
        }
    }
}

class Odd implements Runnable {
    private SharedPrinter sp;
    private int max;

    // standard constructors
    @Override
    public void run() {
        for (int i = 1; i <= max; i = i + 2) {
            sp.printOddNum(i);
        }
    }
}

6. Conclusion

Dans ce didacticiel, nous avons examiné comment imprimer des nombres pairs et impairs en utilisant deux threads en Java. Nous avons examiné deux méthodes pour obtenir les mêmes résultats:using wait() and notify() etusing a Semaphore.

Et, comme toujours, le code de travail complet est disponibleover on GitHub.