Drucken Sie gerade und ungerade Zahlen mit 2 Threads

1. Einleitung

In diesem Tutorial werden wir uns ansehen, wie wir mit zwei Threads gerade und ungerade Zahlen drucken können.

Das Ziel ist es, die Zahlen der Reihe nach 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 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 sich positiv auf die Leistung und die CPU-Auslastung auswirken, da über mehrere parallel laufende Threads mehrere Aufgaben gleichzeitig bearbeitet werden können.

Weitere Informationen zu Threads in Java finden Sie in diesem Artikel.

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

Weitere Informationen zur Verwendung dieser Methoden zum Erstellen eines Threads finden Sie hier.

3. Thread-Synchronisation

In einer Umgebung mit mehreren Threads ist es möglich, dass zwei oder mehr Threads ungefähr zur gleichen Zeit auf dieselbe Ressource zugreifen. Dies kann tödlich 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 durch Thread-Synchronisation erreichen.

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

Weitere Details zur Thread-Synchronisation in Java finden Sie hier.

4. Kommunikation zwischen Threads

Durch die Kommunikation zwischen Threads können synchronisierte Threads mithilfe einer Reihe von Methoden miteinander kommunizieren.

Die verwendeten Methoden sind warten , melden, und notifyAll, die alle von der geerbt werden Objektklasse.

Wait () bewirkt, dass der aktuelle Thread unbegrenzt wartet, bis ein anderer Thread notify () oder notifyAll () für dasselbe Objekt aufruft . Wir können notify () aufrufen , um Threads zu aktivieren, die auf den Zugriff auf den Monitor dieses Objekts warten.

Weitere Details zur Funktionsweise dieser Methoden finden Sie hier.

5. Alternativ können Sie auch ungerade und gerade Zahlen drucken

5.1. Mit wait () und notify ()

Wir werden die diskutierten Konzepte der Synchronisation und der Kommunikation zwischen Threads verwenden, um ungerade und gerade Zahlen in aufsteigender Reihenfolge unter Verwendung von zwei verschiedenen Threads zu drucken.

Im ersten Schritt implementieren wir die Runnable- Schnittstelle, um die Logik beider Threads zu definieren . Bei der Ausführungsmethode prüfen wir, ob die Zahl gerade oder ungerade ist.

Wenn die Zahl gerade ist, rufen wir die printEven- Methode der Printer- Klasse auf, andernfalls 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 Druckerklasse 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 verwenden wir die definierte Klasse, um zwei Threads zu erstellen. Wir erstellen ein Objekt der Printer- Klasse und übergeben es als Parameter an den TaskEvenOdd- Konstruktor:

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 den 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 wie oben definiert auf, wobei wir prüfen, ob die Zahl ungerade oder gerade ist, und sie drucken.

Wenn der ungeradee Faden zu laufen beginnt, wird der Wert der variablen Nummer wird 1 sein , da es weniger ist als die maxValue und das Flag isEvenNumber falsch ist, printOdd () aufgerufen wird. In der Methode prüfen wir, ob das Flag isOdd wahr ist, und rufen währenddessen true () auf. Da isOdd anfangs false ist, wird wait () nicht aufgerufen und der Wert wird gedruckt.

Wir setzen dann den Wert von isOdd auf true, so dass der ungerade Thread in den Wartezustand wechselt und notify () aufruft , um den geraden Thread aufzuwecken. Der gerade Thread wacht dann auf und druckt die gerade Zahl, da das ungerade Flag falsch ist. Anschließend wird notify () aufgerufen, um den ungeraden Thread zu aktivieren.

Das gleiche Verfahren wird durchgeführt , bis der Wert der variablen Anzahl größer ist als die maxValue .

5.2. Verwenden von Semaphoren

Ein Semaphor steuert den Zugriff auf eine gemeinsam genutzte Ressource mithilfe eines Zählers. Wenn der Zähler größer als Null ist, ist der Zugriff zulässig . Wenn es Null ist, wird der Zugriff verweigert.

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

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

Beide Threads haben ein Objekt der SharedPrinter- Klasse. Die SharedPrinter- Klasse verfügt über zwei Semaphoren, semOdd und semEven , für die zunächst 1 und 0 zulässig sind . Dadurch wird sichergestellt, dass zuerst eine ungerade Zahl gedruckt wird.

We have two methods printEvenNum() and printOddNum(). The odd thread calls the printOddNum() method and the even thread calls the printEvenNum() method.

To print an odd number, the acquire() method is called on semOdd, and since the initial permit is 1, it acquires the access successfully, prints the odd number and calls release() on semEven.

Calling release() will increment the permit by 1 for semEven, and the even thread can then successfully acquire the access and print the even number.

This is the code for the workflow described above:

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

In diesem Tutorial haben wir uns angesehen, wie wir ungerade und gerade Zahlen alternativ mit zwei Threads in Java drucken können. Wir hatten einen Blick auf zwei Methoden , um die gleichen Ergebnisse zu erzielen: mit wait () und notify () und mit einer Semaphore .

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