Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lernen Semaphore und Barriere | Hochrangige Synchronisationsmechanismen
Multithreading in Java
course content

Kursinhalt

Multithreading in Java

Multithreading in Java

1. Grundlagen der Multithread-Verarbeitung
2. Synchronisierte Sammlungen
3. Hochrangige Synchronisationsmechanismen
4. Best Practices für Multithreading

book
Semaphore und Barriere

In multithreaded Programmen ist es oft notwendig, den Zugriff auf Ressourcen zu kontrollieren oder die Ausführung von Threads zu synchronisieren. Semaphore und Barrier sind hochrangige Synchronisationsmechanismen, die helfen, diese Herausforderungen zu bewältigen.

Heute werden wir jeden dieser Mechanismen der Reihe nach erkunden und ihre Unterschiede verstehen. Beginnen wir mit Semaphore.

Semaphore in Java werden implementiert durch die java.util.concurrent.Semaphore Klasse.

Konstruktoren

Semaphore(int permits): Konstruktor, der ein semaphore mit einer bestimmten Anzahl von Berechtigungen erstellt. Die Berechtigungen repräsentieren die Anzahl der Zugriffe auf die gemeinsame Ressource.

java

Main

copy
1
Semaphore semaphore = new Semaphore(20);

Semaphore(int permits, boolean fair): Konstruktor, der eine first-come, first-served-Lösung bietet.

java

Main

copy
1
Semaphore semaphore = new Semaphore(20, true);

Wenn fair auf true gesetzt ist, wird das semaphore Berechtigungen in first-in-first-out (FIFO)-Reihenfolge erteilen, was helfen kann, Verhungern zu vermeiden. Standard - false.

Hauptmethoden

Die acquire() Methode fordert eine einzelne Erlaubnis an. Wenn eine Erlaubnis verfügbar ist, wird sie sofort gewährt; andernfalls wird der Thread blockiert, bis eine Erlaubnis verfügbar wird. Sobald eine Aufgabe abgeschlossen ist, wird die release() Methode verwendet, um die Erlaubnis freizugeben und sie an das semaphore zurückzugeben. Wenn andere Threads auf eine Erlaubnis warteten, wird einer von ihnen entblockt.

Stellen Sie sich einen Parkplatz mit einer begrenzten Anzahl von Plätzen vor. Das semaphore fungiert als Kontroller, der die verfügbaren Plätze im Auge behält und den Zugang verweigert, sobald der Parkplatz voll ist.

java

Main

copy
1234567891011121314151617181920212223242526272829303132
package com.example; import java.util.concurrent.Semaphore; public class Main { private final Semaphore semaphore; public Main(int slots) { semaphore = new Semaphore(slots); } public void parkCar() { try { semaphore.acquire(); // Request a parking spot System.out.println("Car parked. Available slots: " + semaphore.availablePermits()); Thread.sleep(2000); // Simulate parking time } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { semaphore.release(); // Release the parking spot System.out.println("Car left. Available slots: " + semaphore.availablePermits()); } } public static void main(String[] args) { Main parking = new Main(3); // Parking lot with 3 spots for (int i = 0; i < 5; i++) { new Thread(parking::parkCar).start(); } } }

Sie können auch herausfinden, wie viele Berechtigungen derzeit in Semaphore verfügbar sind, indem Sie die Methode int availablePermits() verwenden. Sie können auch versuchen, eine Berechtigung zu erhalten, indem Sie die Methode boolean tryAcquire() verwenden, die true zurückgibt, wenn eine Berechtigung erhalten wurde, und false, wenn nicht.

java

Main

copy
1234567891011121314151617181920212223242526272829303132333435363738394041
package com.example; import java.util.concurrent.Semaphore; public class Main { // Define the maximum number of permits available private static final int MAX_PERMITS = 3; private static Semaphore semaphore = new Semaphore(MAX_PERMITS); public static void main(String[] args) { // Create and start 5 worker threads for (int i = 1; i <= 5; i++) { new Thread(new Worker(), "Worker-" + i).start(); } } static class Worker implements Runnable { @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " trying to acquire a permit..."); // Try to acquire a permit if (semaphore.tryAcquire()) { try { System.out.println(name + " acquired a permit! Available permits: " + semaphore.availablePermits()); Thread.sleep(1000); // Simulate work } catch (InterruptedException e) { e.printStackTrace(); } finally { // Release the permit after the work is done semaphore.release(); System.out.println(name + " released a permit. Available permits: " + semaphore.availablePermits()); } } else { // Inform if the permit could not be acquired System.out.println(name + " could not acquire a permit. Available permits: " + semaphore.availablePermits()); } } } }

Ergebnisse

Mit anderen Worten, ein Semaphore ist nützlich, wenn Sie begrenzten gleichzeitigen Zugriff auf ein bestimmtes Code-Segment bereitstellen müssen. Der einzige Nachteil ist die Möglichkeit eines Deadlocks, wenn Threads in der falschen Reihenfolge blockiert werden.

Kommen wir nun zum nächsten Synchronisationsmechanismus, der noch einfacher zu verwenden ist, aber für Ihre Bedürfnisse 100 Prozent wertvoll sein wird.

CyclicBarrier

Barrier in Java werden durch die Klasse java.util.concurrent.CyclicBarrier repräsentiert. Die Hauptmethoden von CyclicBarrier umfassen:

Konstruktoren CyclicBarrier

CyclicBarrier(int parties): Konstruktor, der eine Barriere erstellt, die Threads blockiert, bis eine bestimmte Anzahl von Threads (Parties) ankommt.

java

Main

copy
1
CyclicBarrier cyclicBarrier = new CyclicBarrier(10);

CyclicBarrier(int parties, Runnable barrierAction): Konstruktor, der eine Barriere mit einer bestimmten Anzahl von Parteien und einer Aktion (barrierAction) erstellt, die ausgeführt wird, wenn alle Parteien die Barriere erreichen.

java

Main

copy
1234567
Runnable task = () -> { // This task will be executed when all parties have reached the barrier System.out.println("Hello))"); }; // Create a `CyclicBarrier` for 10 parties with a barrier action CyclicBarrier cyclicBarrier = new CyclicBarrier(10, task);

Methoden CyclicBarrier

Die Hauptmethode await(), die als Barriere verwendet wird und den Thread nicht weitergehen lässt, bis alle Threads diese Methode erreicht haben. Gibt eine Sequenznummer zurück, die die Reihenfolge der Ankunft der Teilnehmer angibt.

java

Main

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344
package com.example; import java.util.concurrent.CyclicBarrier; public class Main { public static void main(String[] args) { // Create a `CyclicBarrier` for 3 parties with a barrier action CyclicBarrier barrier = new CyclicBarrier(3, () -> { System.out.println("All parties have reached the barrier. Barrier action executed."); }); // Create and start 3 worker threads for (int i = 1; i <= 3; i++) { new Thread(new Worker(barrier), "Worker-" + i).start(); } } static class Worker implements Runnable { private CyclicBarrier barrier; Worker(CyclicBarrier barrier) { this.barrier = barrier; } @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " is working..."); try { // Simulate work Thread.sleep((int) (Math.random() * 1000)); System.out.println(name + " is waiting at the barrier."); barrier.await(); // Wait at the barrier // This code will execute after all parties have reached the barrier System.out.println(name + " has crossed the barrier."); } catch (Exception e) { e.printStackTrace(); } } } }

Es kann vorkommen, dass nicht alle Threads die Barriere erreichen und das Programm hängt, zu diesem Zweck wird die Methode await(long timeout, TimeUnit unit) verwendet, die ähnlich wie await() ist, jedoch mit Timeout. Wenn der Timeout abläuft, bevor alle Teilnehmer eintreffen, erzeugt die Methode eine TimeoutException Ausnahme.

Sie können auch die Anzahl der Teilnehmer herausfinden, die erforderlich sind, um die Barriere zu vervollständigen int getParties() und seine ähnliche Methode int getNumberWaiting(), die die Anzahl der Teilnehmer, die derzeit an der Barriere warten, zurückgibt.

java

Main

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
package com.example; import java.util.concurrent.CyclicBarrier; public class Main { public static void main(String[] args) { // Create a `CyclicBarrier` for 3 parties with a barrier action CyclicBarrier barrier = new CyclicBarrier(3, () -> { System.out.println("All parties have reached the barrier. Barrier action executed."); }); System.out.println("Total number of parties required to complete the barrier: " + barrier.getParties()); // Create and start 3 worker threads for (int i = 1; i <= 3; i++) { new Thread(new Worker(barrier), "Worker-" + i).start(); } } static class Worker implements Runnable { private CyclicBarrier barrier; Worker(CyclicBarrier barrier) { this.barrier = barrier; } @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " is working..."); try { // Simulate work Thread.sleep((int) (Math.random() * 1000)); System.out.println(name + " is waiting at the barrier."); barrier.await(); // Wait at the barrier // This code will execute after all parties have reached the barrier System.out.println(name + " has crossed the barrier."); } catch (Exception e) { e.printStackTrace(); } // Print the number of participants currently waiting at the barrier System.out.println("Number of participants currently waiting at the barrier: " + barrier.getNumberWaiting()); } } }

Es ist auch möglich zu überprüfen, ob die Barriere zerstört wurde, wenn einer der Threads unterbrochen wird oder die Wartezeit abgelaufen ist, indem die boolean isBroken() Methode verwendet wird. Wenn sie gebrochen wurde, können Sie die void reset() Methode verwenden, die die Barriere einfach wiederherstellt.

java

Main

copy
12345
// Check if the barrier is broken and reset it if necessary if (barrier.isBroken()) { System.out.println("Barrier is broken. Resetting the barrier."); barrier.reset(); }

Hinweis

Es sollte berücksichtigt werden, dass einige Abläufe die Barriere möglicherweise nicht erreichen, aufgrund eines Fehlers oder etwas anderem, und dann ist klar, dass die Barriere jene Abläufe, die derzeit an der Barriere warten, nicht passieren lässt.

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 3. Kapitel 3
We're sorry to hear that something went wrong. What happened?
some-alt