Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lernen BlockingQueue und Seine Implementierungen | Synchronisierte Sammlungen
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
BlockingQueue und Seine Implementierungen

Grundlegende BlockingQueue-Implementierungen

Wir werden nicht jede Realisierung im Detail durchgehen, da es viel Zeit in Anspruch nehmen würde und es unwahrscheinlich ist, dass Sie sie alle benötigen. Ich werde über die allgemeinen Konzepte und welche Konstruktoren sie haben, sprechen.

Beispiel aus dem echten Leben

Stellen Sie sich eine Fabrik vor, in der ein Thread, der Produzent, Teile erstellt und ein anderer Thread, der Konsument, diese verarbeitet. Der Produzent legt die Teile in eine Warteschlange, während der Konsument sie aus der Warteschlange abruft und verarbeitet. Wenn die Warteschlange keine Teile mehr hat, wartet der Konsument darauf, dass der Produzent mehr hinzufügt. Umgekehrt wartet der Produzent, wenn die Warteschlange voll ist, darauf, dass der Konsument Platz schafft.

Hinweis

Etwas weiter unten werden wir diese Aufgabe im Code implementieren.

Unterschiede zu anderen Sammlungstypen

Die BlockingQueue bietet automatische Synchronisation, die den Thread-Zugriff auf die Warteschlange verwaltet, ohne dass eine manuelle Synchronisation erforderlich ist. Sie unterstützt auch blockierende Operationen zum Hinzufügen und Abrufen von Elementen, eine Funktion, die in anderen Sammlungen wie ArrayList oder LinkedList nicht vorhanden ist.

Implementierungen von BlockingQueue

ArrayBlockingQueue: Eine größenbeschränkte Warteschlange, die ein Array zur Speicherung von Elementen verwendet.

java

Main

copy
123456789
// Constructor with fixed capacity BlockingQueue<String> queue1 = new ArrayBlockingQueue<>(5); // Constructor with fixed capacity and fair access BlockingQueue<String> queue2 = new ArrayBlockingQueue<>(5, true); // Constructor with fixed capacity and initial collection of elements Collection<String> initialElements = java.util.Arrays.asList("One", "Two", "Three"); BlockingQueue<String> queue3 = new ArrayBlockingQueue<>(5, false, initialElements);

Erklärung

Der true Parameter ermöglicht eine faire Zugriffspolitik, indem er eine FIFO-Reihenfolge für den Thread-Zugriff bereitstellt.

LinkedBlockingQueueue: Eine Warteschlange basierend auf verketteten Knoten, die beschränkt oder unbeschränkt sein kann.

java

Main

copy
123456789
// Constructor without capacity bounds BlockingQueue<String> queue1 = new LinkedBlockingQueue<>(); // Constructor with fixed capacity BlockingQueue<String> queue2 = new LinkedBlockingQueue<>(5); // Constructor with initial collection of elements Collection<String> initialElements = java.util.Arrays.asList("One", "Two", "Three"); BlockingQueue<String> queue3 = new LinkedBlockingQueue<>(initialElements);

PriorityBlockingQueue: Eine unbegrenzte priorisierte Warteschlange, bei der Elemente gemäß ihrer natürlichen Reihenfolge oder wie durch einen Comparator angegeben abgerufen werden.

java

Main

copy
12345678910111213
// Constructor without initial capacity (default is 11) BlockingQueue<Integer> queue1 = new PriorityBlockingQueue<>(); // Constructor with initial capacity BlockingQueue<Integer> queue2 = new PriorityBlockingQueue<>(5); // Constructor with initial capacity and comparator Comparator<Integer> comparator = Integer::compareTo; BlockingQueue<Integer> queue3 = new PriorityBlockingQueue<>(5, comparator); // Constructor with initial collection of elements Collection<Integer> initialElements = java.util.Arrays.asList(1, 3, 2); BlockingQueue<Integer> queue4 = new PriorityBlockingQueue<>(initialElements)

DelayQueue: Eine verzögerte Warteschlange, bei der Elemente erst nachdem ihre Verzögerung abgelaufen ist, abgerufen werden können.

java

DelayedElement

java

DelayQueueConstructors

copy
123456789101112131415161718
class DelayedElement implements Delayed { private final long expirationTime; // The time when the element will be available public DelayedElement(long delay, TimeUnit unit) { this.expirationTime = System.currentTimeMillis() + unit.toMillis(delay); } @Override public long getDelay(TimeUnit unit) { long delay = expirationTime - System.currentTimeMillis(); // Calculate the remaining delay return unit.convert(delay, TimeUnit.MILLISECONDS); // Convert the delay to the specified time unit } @Override public int compareTo(Delayed o) { return Long.compare(this.expirationTime, ((DelayedElement) o).expirationTime); } }

Dieser Code demonstriert die Verwendung der DelayedElement-Klasse, die das Delayed-Interface implementiert, und der DelayQueue-Verzögerungswarteschlange in Java. Die DelayedElement-Klasse definiert eine getDelay-Methode, um die verbleibende Verzögerungszeit zu berechnen, und eine compareTo-Methode, um Objekte basierend auf der Verzögerungsablaufzeit zu vergleichen.

Die main-Methode erstellt zwei Warteschlangen: queue1, eine leere Verzögerungswarteschlange, und queue2, eine Warteschlange, die mit Elementen initialisiert ist, die eine Verzögerung von 5 bzw. 1 Sekunde haben.

Die Elemente in DelayQueueue werden verfügbar zur Abholung, nachdem die angegebene Verzögerungszeit abgelaufen ist.

SynchronousQueueue: Eine Warteschlange ohne Kapazität, bei der jede Einfügeoperation auf die entsprechende Extraktionsoperation warten muss und umgekehrt.

java

Main

copy
12345
// Constructor without fair access BlockingQueue<String> queue1 = new SynchronousQueue<>(); // Constructor with fair access BlockingQueue<String> queue2 = new SynchronousQueue<>(true);

Die Hauptmethoden der BlockingQueue:

Hinzufügen von Elementen:

Die void put(E e) Methode fügt ein Element in die Warteschlange ein und blockiert den Thread, wenn die Warteschlange voll ist. Alternativ versucht die boolean offer(E e, long timeout, TimeUnit unit) Methode, ein Element in die Warteschlange einzufügen und wartet die angegebene Zeit, wenn die Warteschlange voll ist.

java

Main

copy
1234567891011121314151617
public class BlockingQueueExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { queue.put("Element 1"); // Insert the first element, no blocking. queue.put("Element 2"); // Insert the second element, no blocking. // Try to add the third element with a 2-second timeout. // Since the queue is full, it will wait for 2 seconds. boolean success = queue.offer("Element 3", 2, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } }

Dieses Beispiel zeigt das Einfügen von zwei Elementen in eine BlockingQueue ohne Blockierung, gefolgt von einem Versuch, ein drittes Element mit einem 2-Sekunden-Timeout mithilfe der offer()-Methode hinzuzufügen, die wartet, wenn die Warteschlange voll ist.

Elementabruf:

Die E take() Methode ruft ein Element aus der Warteschlange ab und gibt es zurück, wobei der Thread blockiert wird, wenn die Warteschlange leer ist. Alternativ versucht die E poll(long timeout, TimeUnit unit) Methode, ein Element aus der Warteschlange abzurufen und wartet die angegebene Zeit, wenn die Warteschlange leer ist.

java

Main

copy
1234567891011121314151617181920212223
public class BlockingQueueRetrievalExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Retrieve and remove the first element, no blocking since the queue is not empty String item1 = queue.take(); // Returns "Element 1" // Attempt to retrieve and remove the next element with a 2-second timeout String item2 = queue.poll(2, TimeUnit.SECONDS); // Returns "Element 2" // Attempt to retrieve an element when the queue is empty, this will block for 2 seconds String item3 = queue.poll(2, TimeUnit.SECONDS); // Returns `null` after timeout } catch (InterruptedException e) { e.printStackTrace(); } } }

Dieser Code fügt zwei Elemente zu einer BlockingQueue hinzu, ruft und entfernt das erste Element sofort, versucht, das nächste Element mit einem 2-Sekunden-Timeout abzurufen, und versucht schließlich, ein Element aus einer leeren Warteschlange abzurufen, was nach dem Timeout zu einem null führt.

Überprüfen und Entfernen von Elementen:

Die boolean remove(Object o) Methode entfernt das angegebene Element aus der Warteschlange, wenn es vorhanden ist. Andererseits überprüft die boolean contains(Object o) Methode, ob das angegebene Element in der Warteschlange vorhanden ist, ohne es zu entfernen.

java

Main

copy
1234567891011121314151617181920212223242526
public class BlockingQueueCheckRemoveExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(2); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Check if "Element 1" is in the queue, should return `true` boolean containsElement1 = queue.contains("Element 1"); // true // Remove "Element 1" from the queue, should return `true` boolean removedElement1 = queue.remove("Element 1"); // true // Check if "Element 1" is still in the queue, should return `false` boolean containsElement1AfterRemoval = queue.contains("Element 1"); // false // Try to remove an element that is not in the queue, should return `false` boolean removedElement3 = queue.remove("Element 3"); // false } catch (InterruptedException e) { e.printStackTrace(); } } }

Dieser Code fügt zwei Elemente zu einer BlockingQueue hinzu, überprüft das Vorhandensein von "Element 1", entfernt es, überprüft erneut, um seine Entfernung zu bestätigen, und versucht dann, ein nicht vorhandenes Element zu entfernen.

Überprüft den Zustand der Warteschlange:

Die int size() Methode gibt die Anzahl der Elemente zurück, die sich derzeit in der Warteschlange befinden. Um festzustellen, ob die Warteschlange leer ist, können Sie die boolean isEmpty() Methode verwenden, die überprüft, ob die Warteschlange keine Elemente hat. Für Warteschlangen mit einer festen Kapazität bietet die int remainingCapacity() Methode die Anzahl der verbleibenden verfügbaren Plätze in der Warteschlange.

java

Main

copy
123456789101112131415161718192021222324252627282930
public class BlockingQueueCapacityExample { public static void main(String[] args) { BlockingQueue<String> queue = new ArrayBlockingQueue<>(3); try { // Adding elements to the queue queue.put("Element 1"); queue.put("Element 2"); // Get the number of elements in the queue int currentSize = queue.size(); // 2 // Check if the queue is empty boolean isQueueEmpty = queue.isEmpty(); // false // Get the remaining capacity in the queue int remainingSpace = queue.remainingCapacity(); // 1 // Add another element to fill the queue queue.put("Element 3"); // Check the size and remaining capacity after adding the third element currentSize = queue.size(); // 3 remainingSpace = queue.remainingCapacity(); // 0 } catch (InterruptedException e) { e.printStackTrace(); } } }

Dieser Code fügt Elemente hinzu zu einer BlockingQueue, überprüft die aktuelle Größe, verifiziert, ob die Warteschlange leer ist, und bestimmt die verbleibende Kapazität, dann aktualisiert er diese Werte, nachdem die Warteschlange vollständig gefüllt wurde.

Ein reales Beispiel im Code umsetzen

😭 Einschränkungen

Eine wesentliche Einschränkung ist die Leistung: Aufgrund der Sperroperationen kann die Leistung im Vergleich zu nicht-synchronisierten Sammlungen reduziert werden. Darüber hinaus können Ressourcen ein Problem darstellen, da große Warteschlangen mehr Speicher und CPU-Zeit benötigen, um die Sperren und Synchronisationsprozesse zu handhaben.

💪 Vorteile

Auf der positiven Seite ist das System sicher im Multithreading, bietet sichere Kommunikation zwischen Threads, ohne dass eine manuelle Synchronisationsverwaltung erforderlich ist. Es vereinfacht auch den Code, indem es komplexe Synchronisations- und Blockierungskonstrukte vermeidet. Darüber hinaus bedeutet die Flexibilität der verschiedenen BlockingQueue-Implementierungen, dass sie für verschiedene Nutzungsszenarien geeignet sein können.

1. Was ist eine BlockingQueue in Java?

2. Was sind die Hauptmethoden von BlockingQueue, die einen Thread blockieren?

3. Wofür ist BlockingQueue in Multithread-Anwendungen nützlich?

Was ist eine BlockingQueue in Java?

Was ist eine BlockingQueue in Java?

Wählen Sie die richtige Antwort aus

Was sind die Hauptmethoden von BlockingQueue, die einen Thread blockieren?

Was sind die Hauptmethoden von BlockingQueue, die einen Thread blockieren?

Wählen Sie die richtige Antwort aus

Wofür ist BlockingQueue in Multithread-Anwendungen nützlich?

Wofür ist BlockingQueue in Multithread-Anwendungen nützlich?

Wählen Sie die richtige Antwort aus

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

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