Gerade und ungerade Zahlen mit 2 Threads drucken

1. Einleitung

In diesem Lernprogramm werden wir sehen, wie wir mit zwei Threads gerade und ungerade Zahlen drucken können.

Das Ziel ist, die Zahlen in der richtigen Reihenfolge zu drucken, während ein Thread nur die geraden Zahlen und der andere Thread nur die ungeraden Zahlen druckt. Wir werden die Konzepte der Thread-Synchronisation und der Kommunikation zwischen den Threads verwenden, um das Problem zu lösen.

2. Threads in Java

Threads sind einfache Prozesse, die gleichzeitig ausgeführt werden können.

Die gleichzeitige Ausführung mehrerer Threads kann in Bezug auf Leistung und CPU-Auslastung eine gute Rolle spielen, da über mehrere parallel laufende Threads hinweg mehrere Aufgaben gleichzeitig bearbeitet werden können.

Weitere Informationen zu Threads in Java finden Sie unter https://www.baeldung.com/java-thread-lifecycle [article

In Java können Sie einen Thread erstellen, indem Sie entweder die Thread -Klasse erweitern oder die Runnable -Schnittstelle implementieren ** . In beiden Fällen überschreiben wir die run -Methode und schreiben die Implementierung des Threads darin.

Weitere Informationen zur Verwendung dieser Methoden zum Erstellen eines Threads finden Sie hier: https://www.baeldung.com/java-runnable-vs-extending-thread

3. Thread-Synchronisierung

In einer Umgebung mit mehreren Threads kann es vorkommen, dass zwei oder mehr Threads ungefähr gleichzeitig auf dieselbe Ressource zugreifen. Dies kann fatal sein und zu fehlerhaften Ergebnissen führen. Um dies zu verhindern, müssen wir sicherstellen, dass zu einem bestimmten Zeitpunkt nur ein Thread auf die Ressource zugreift.

Dies können wir mit der Thread-Synchronisation erreichen.

  • In Java können wir eine Methode oder einen Block als synchronisiert markieren, was bedeutet, dass nur ein Thread diese Methode oder den Block zu einem bestimmten Zeitpunkt eingeben kann. **

Weitere Informationen zur Thread-Synchronisierung in Java finden Sie unter hier. .

4. Inter-Thread-Kommunikation

Die Kommunikation zwischen Threads ermöglicht es synchronisierten Threads, unter Verwendung einer Reihe von Methoden miteinander zu kommunizieren.

Die verwendeten Methoden sind wait , notify, und notifyAll, , die alle von der Object -Klasse übernommen werden.

  • Wait () bewirkt, dass der aktuelle Thread unbestimmt wartet, bis ein anderer Thread notify () oder notifyAll () für dasselbe Objekt aufruft Monitor.

Weitere Einzelheiten zur Funktionsweise dieser Methoden finden Sie unter https://www.baeldung.com/java-wait-notify (hier).

5. Ungerade und gerade Zahlen alternativ drucken

5.1. Wait () und notify () verwenden

Wir werden die diskutierten Konzepte der Synchronisation und Inter-Thread-Kommunikation verwenden, um ungerade und gerade Zahlen in aufsteigender Reihenfolge mit zwei verschiedenen Threads zu drucken.

Im ersten Schritt implementieren wir die Runnable -Schnittstelle, um die Logik beider Threads zu definieren. In der run -Methode überprüfen wir, ob die Anzahl gerade oder ungerade ist.

Wenn die Anzahl gerade ist, rufen wir die printEven -Methode der Printer -Klasse auf, ansonsten rufen wir die printOdd -Methode auf:

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;
        }
    }
}

Wir definieren die Printer -Klasse wie folgt:

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 der Hauptmethode erstellen wir mit der definierten Klasse zwei Threads. ** Wir erstellen ein Objekt der Klasse Printer und übergeben es als Parameter an den Konstruktor TaskEvenOdd :

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();
}

Der erste Thread ist der ungerade Thread. Daher übergeben wir false als Wert des Parameters isEvenNumber . Für den zweiten Thread übergeben wir stattdessen true . Wir setzen maxValue für beide Threads auf 10, sodass nur die Zahlen von 1 bis 10 gedruckt werden.

Wir starten dann beide Threads, indem wir die start () -Methode aufrufen. Dies ruft die run () -Methode beider Threads auf, wie oben definiert, wobei wir prüfen, ob die Anzahl gerade oder ungerade ist, und sie drucken.

Wenn der ungerade Thread gestartet wird, ist der Wert der Variablen number 1. Wenn er kleiner als maxValue ist und das Flag isEvenNumber falsch ist, wird printOdd () aufgerufen. In der Methode überprüfen wir, ob das Flag isOdd wahr ist, und während es wahr ist, rufen wir _wait () auf. Da isOdd anfangs falsch ist, wird wait () _ nicht aufgerufen und der Wert wird gedruckt.

Dann setzen wir den Wert von isOdd auf true, sodass der ungerade Thread in den Wartezustand wechselt und notify () ** aufruft, um den geraden Thread aufzuwecken. Der gerade Thread wird dann aktiviert und gibt die gerade Zahl aus, da das odd -Flag false ist. Dann ruft er notify () auf, um den ungeraden Thread aufzuwecken.

Der gleiche Prozess wird ausgeführt, bis der Wert der Variablen number größer ist als der maxValue .

5.2. Verwendung von Semaphoren

Ein Semaphor steuert den Zugriff auf eine gemeinsam genutzte Ressource mithilfe eines Zählers. Ist der Zähler größer als Null, ist der Zugriff erlaubt .

Wenn es Null ist, wird der Zugriff verweigert.

Java stellt die Semaphore -Klasse im java.util.concurrent -Paket bereit, und wir können damit den erläuterten Mechanismus implementieren. Weitere Details zu Semaphoren finden Sie unter hier .

Wir erstellen zwei Threads, einen ungeraden Thread und einen geraden Thread. Der ungerade Faden druckt die ungeraden Zahlen beginnend mit 1 und der gerade Faden druckt die geraden Zahlen ab 2.

Beide Threads haben ein Objekt der Klasse SharedPrinter . Die SharedPrinter -Klasse hat zwei Semaphoren, semOdd und _semEven _ , die 1 und 0 haben, um mit zu beginnen. Dadurch wird sichergestellt, dass die ungerade Zahl zuerst gedruckt wird.

Wir haben zwei Methoden, printEvenNum () und _printOddNum (). Der ungerade Thread ruft die Methode printOddNum () und der gerade Thread die Methode printEvenNum () _ auf.

Um eine ungerade Zahl zu drucken, wird die acquire () -Methode für semOdd aufgerufen. Da die anfängliche Berechtigung 1 ist, erhält sie den Zugriff erfolgreich, gibt die ungerade Zahl aus und ruft release () on semEven. auf.

Durch Aufrufen von release () wird die Berechtigung für semEven um 1 erhöht. Der gerade Thread kann dann den Zugriff erfolgreich abrufen und die gerade Zahl drucken.

Dies ist der Code für den oben beschriebenen Workflow:

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. Schlussfolgerung

In diesem Tutorial haben wir uns angesehen, wie wir ungerade und gerade Zahlen alternativ mithilfe von zwei Threads in Java drucken können. Wir haben uns zwei Methoden angesehen, um dieselben Ergebnisse zu erzielen: using wait () und notify () und mit einem Semaphore _. _

Und wie immer ist der vollständige Arbeitscode verfügbar: over auf GitHub .