Einleitung: Warum braucht man Aufgabenwarteschlangen in Java?
\n\nJeder Entwickler steht früher oder später vor der Notwendigkeit, eine Streaming-Datenverarbeitung zu organisieren. Stellen Sie sich einen Webserver vor, der Tausende von Anfragen pro Sekunde empfängt, oder ein System, das Bestellungen eines Online-Shops verarbeitet. Alles auf einmal zu verarbeiten ist unmöglich – die Ressourcen sind begrenzt. Hier helfen Aufgabenwarteschlangen (task queues).
\n\nIn Java ist eine Aufgabenwarteschlange nicht nur eine FIFO-Datenstruktur (First In, First Out). Es ist ein leistungsstarkes Werkzeug für:
\n- \n
- Trennung von Aufgabenproduktion und -konsum (Producer-Consumer-Muster) \n
- Lastmanagement – Aufgaben sammeln sich in der Warteschlange, wenn das System ausgelastet ist \n
- Asynchrone Verarbeitung – der Producer-Thread wartet nicht, bis die Aufgabe abgeschlossen ist \n
- Lastverteilung zwischen Threads – mehrere Worker holen Aufgaben aus einer gemeinsamen Warteschlange \n
In diesem Artikel werden wir alle wesentlichen Aspekte der Arbeit mit Warteschlangen in Java behandeln: von den grundlegenden Schnittstellen des Collection Framework bis hin zu threadsicheren Warteschlangen für Multithread-Anwendungen.
\n\nBasiswarteschlangen: Queue und Deque
\n\nDas Queue-Interface
\n\nDas Interface java.util.Queue ist die Grundlage aller Warteschlangen in Java. Es bietet Standardoperationen für die Arbeit mit einer Warteschlange:
| Operation | Ausnahme bei Fehler | Rückgabe eines speziellen Werts |
|---|---|---|
| Hinzufügen | add(e) | offer(e) |
| Abrufen und Entfernen | remove() | poll() |
| Ansehen (ohne Entfernen) | element() | peek() |
Der Unterschied zwischen den Methoden ist offensichtlich: Wenn die Warteschlange leer ist, werfen remove() und element() eine NoSuchElementException, während poll() und peek() null zurückgeben.
Die beliebtesten Queue-Implementierungen:
\n- \n
- LinkedList – eine doppelt verkettete Liste, funktioniert wie eine normale FIFO-Warteschlange \n
- PriorityQueue – eine Prioritätswarteschlange, Elemente werden in der durch einen Comparator festgelegten Reihenfolge abgerufen \n
- ArrayDeque – eine zweiseitige Warteschlange basierend auf einem Array \n
Beispiel: Einfache Aufgabenwarteschlange mit LinkedList
\n\nimport java.util.LinkedList;\nimport java.util.Queue;\n\npublic class SimpleTaskQueue {\n public static void main(String[] args) {\n Queue<String> taskQueue = new LinkedList<>();\n\n // Aufgaben hinzufügen\n taskQueue.offer("Daten aus der DB laden");\n taskQueue.offer("E-Mail-Benachrichtigung senden");\n taskQueue.offer("Bericht generieren");\n\n System.out.println("Warteschlange: " + taskQueue);\n\n // Alle Aufgaben verarbeiten\n while (!taskQueue.isEmpty()) {\n String task = taskQueue.poll();\n System.out.println("Führe aus: " + task);\n }\n\n System.out.println("Alle Aufgaben erledigt!");\n }\n}\n\nDas Deque-Interface
\n\nDeque (Double Ended Queue) ermöglicht das Hinzufügen und Entfernen von Elementen an beiden Enden. Dies bietet Flexibilität: Die Warteschlange kann als Stapel (LIFO) oder als normale Warteschlange (FIFO) arbeiten.
Wichtige Methoden von Deque:
\n- \n
addFirst()/offerFirst()– am Anfang hinzufügen \n addLast()/offerLast()– am Ende hinzufügen \n removeFirst()/pollFirst()– vom Anfang abrufen \n removeLast()/pollLast()– vom Ende abrufen \n
Beispiel: Deque als Stapel für verzögerte Aufgaben
\n\nimport java.util.ArrayDeque;\nimport java.util.Deque;\n\npublic class DequeExample {\n public static void main(String[] args) {\n De