Anleitung zur Java Queue-Schnittstelle

1. Einleitung

In diesem Tutorial werden wir die Warteschlangenoberfläche von Java erläutern .

Zunächst werfen wir einen Blick auf die Funktionsweise einer Warteschlange und einige ihrer Kernmethoden . Als nächstes werden wir uns mit einer Reihe von Implementierungen befassen, die Java standardmäßig bereitstellt.

Schließlich werden wir über die Thread-Sicherheit sprechen, bevor wir alles zusammenfassen.

2. Visualisierung der Warteschlange

Beginnen wir mit einer kurzen Analogie.

Stellen Sie sich vor, wir haben gerade unser erstes Geschäft eröffnet - einen Hot Dog Stand. Wir möchten unsere neuen potenziellen Kunden so effizient wie möglich für unser kleines Unternehmen bedienen. eins nach dem anderen. Zunächst bitten wir sie, vor unserem Stand eine geordnete Linie zu bilden, wobei sich hinten neue Kunden anschließen. Dank unserer organisatorischen Fähigkeiten können wir unsere leckeren Hot Dogs jetzt fair verteilen.

Warteschlangen in Java funktionieren ähnlich. Nachdem wir unsere Warteschlange deklariert haben , können wir der Rückseite neue Elemente hinzufügen und diese von der Vorderseite entfernen.

Tatsächlich funktionieren die meisten Warteschlangen, auf die wir in Java stoßen, auf diese Art und Weise - oft mit FIFO abgekürzt.

Es gibt jedoch eine Ausnahme, auf die wir später noch eingehen werden.

3. Kernmethoden

Die Warteschlange deklariert eine Reihe von Methoden, die von allen implementierenden Klassen codiert werden müssen. Lassen Sie uns jetzt einige der wichtigsten skizzieren :

  1. quote () - Fügt ein neues Element in die Warteschlange ein
  2. poll () - Entfernt ein Element von der Vorderseite der Warteschlange
  3. peek () - Überprüft das Element an der Vorderseite der Warteschlange, ohne es zu entfernen

4. AbstractQueue

AbstractQueue ist die einfachste von Java bereitgestellte Queue- Implementierung. Es enthält eine skelettartige Implementierung einiger Methoden der Warteschlangenschnittstelle , ausgenommen Angebot .

Wenn wir eine individuelle Warteschlange erstellen Verlängerung der AbstractQueue Klasse , müssen wir eine Implementierung vorzusehen des Angebotsverfahren , die sich nicht das Einfügen von Null - Elemente erlauben.

Zusätzlich müssen wir die Methoden peek, poll, size und den Iterator von java.util bereitstellen .

Lassen Sie uns mit AbstractQueue eine einfache Queue- Implementierung zusammenstellen .

Definieren wir zunächst unsere Klasse mit einer LinkedList , um die Elemente unserer Warteschlange zu speichern :

public class CustomBaeldungQueue extends AbstractQueue { private LinkedList elements; public CustomBaeldungQueue() { this.elements = new LinkedList(); } }

Als nächstes überschreiben wir die erforderlichen Methoden und geben den Code ein:

@Override public Iterator iterator() { return elements.iterator(); } @Override public int size() { return elements.size(); } @Override public boolean offer(T t) { if(t == null) return false; elements.add(t); return true; } @Override public T poll() { Iterator iter = elements.iterator(); T t = iter.next(); if(t != null){ iter.remove(); return t; } return null; } @Override public T peek() { return elements.getFirst(); }

Hervorragend, lassen Sie uns überprüfen, ob es mit einem schnellen Unit-Test funktioniert:

customQueue.add(7); customQueue.add(5); int first = customQueue.poll(); int second = customQueue.poll(); assertEquals(7, first); assertEquals(5, second);

4. Subschnittstellen

Im Allgemeinen wird die Warteschlangenschnittstelle von drei Hauptunterschnittstellen geerbt . Blockieren von Warteschlangen, Übertragungswarteschlangen und Deques .

Zusammen werden diese drei Schnittstellen von der überwiegenden Mehrheit der verfügbaren Java- Warteschlangen implementiert . Lassen Sie uns einen kurzen Blick darauf werfen, wozu diese Schnittstellen gedacht sind.

4.1. Warteschlangen blockieren

Die BlockingQueue- Schnittstelle unterstützt zusätzliche Vorgänge, bei denen Threads abhängig vom aktuellen Status gezwungen werden, in der Warteschlange zu warten . Ein Thread wartet möglicherweise darauf, dass die Warteschlange beim Versuch eines Abrufs nicht leer ist oder beim Hinzufügen eines neuen Elements leer wird .

Standard Blocking - Warteschlangen gehören LinkedBlockingQueue, SynchronousQueue, und ArrayBlockingQueue .

Weitere Informationen finden Sie in unserem Artikel zum Blockieren von Warteschlangen .

4.2. Warteschlangen übertragen

The TransferQueue interface extends the BlockingQueue interface but is tailored toward the producer-consumer pattern. It controls the flow of information from producer to consumer, creating backpressure in the system.

Java ships with one implementation of the TransferQueue interface, LinkedTransferQueue.

4.3. Deques

Deque is short for Double-Ended Queue and is analogous to a deck of cards – elements may be taken from both the start and end of the Deque. Much like the traditional Queue, the Deque provides methods to add, retrieve and peek at elements held at both the top and bottom.

For a detailed guide on how the Deque works, check out our ArrayDeque article.

5. Priority Queues

We saw earlier that most of the Queues that we come across in Java follow the FIFO principle.

One such exception to this rule is the PriorityQueue. When new elements are inserted into the PriorityQueue, they are ordered based on their natural ordering, or by a defined Comparator provided when we construct the PriorityQueue.

Let's take a look at how this works with a simple unit test:

PriorityQueue integerQueue = new PriorityQueue(); integerQueue.add(9); integerQueue.add(2); integerQueue.add(4); int first = integerQueue.poll(); int second = integerQueue.poll(); int third = integerQueue.poll(); assertEquals(2, first); assertEquals(4, second); assertEquals(9, third);

Despite the order in which our integers were added to the PriorityQueue, we can see that the retrieval order is changed according to the natural order of the numbers.

We can see that the same is also true when applied to Strings:

PriorityQueue stringQueue = new PriorityQueue(); stringQueue.add("blueberry"); stringQueue.add("apple"); stringQueue.add("cherry"); String first = stringQueue.poll(); String second = stringQueue.poll(); String third = stringQueue.poll(); assertEquals("apple", first); assertEquals("blueberry", second); assertEquals("cherry", third);

6. Thread Safety

Adding items to Queues is particularly useful in multi-threaded environments. A Queue can be shared amongst threads, and be used to block progress until space is available – helping us overcome some common multi-threaded problems.

For example, writing to a single disk from multiple threads creates resource contention and can lead to slow writing times. Creating a single writer thread with a BlockingQueue can alleviate this issue and lead to vastly improved write speeds.

Luckily, Java offers ConcurrentLinkedQueue, ArrayBlockingQueue, and ConcurrentLinkedDeque which are thread-safe and perfect for multi-threaded programs.

7. Conclusion

In diesem Tutorial haben wir uns eingehend mit der Java Queue- Oberfläche befasst.

Zunächst haben wir untersucht, was eine Warteschlange tut und welche Implementierungen Java bietet.

Als nächstes haben wir uns das übliche FIFO-Prinzip einer Warteschlange sowie die PriorityQueue angesehen, die sich in ihrer Reihenfolge unterscheidet.

Schließlich untersuchten wir die Thread-Sicherheit und wie Warteschlangen in einer Umgebung mit mehreren Threads verwendet werden können.

Wie immer ist der Code auf GitHub verfügbar.