Einleitung: Warum braucht man Aufgabenwarteschlangen in Kotlin?
\nModerne Anwendungen erfordern zunehmend parallele Datenverarbeitung, Hintergrundoperationen und asynchrone Aufrufe. Ohne ein durchdachtes Aufgabenmanagement kann Ihr Code auf Leistungsprobleme, Speicherlecks oder „Einfrieren“ der Benutzeroberfläche stoßen. Aufgabenwarteschlangen in Kotlin sind nicht nur eine Abstraktion, sondern ein leistungsstarkes Werkzeug, das hilft, die Ausführung von Arbeiten in der richtigen Reihenfolge zu organisieren, mit Kontrolle über die Anzahl der Threads und Prioritäten.
\nIn diesem Artikel werden wir praktische Ansätze zur Implementierung von Aufgabenwarteschlangen in Kotlin durchgehen: vom klassischen ThreadPoolExecutor bis hin zu Coroutines mit ihren flexiblen Dispatchern. Sie werden sehen, wie Sie diese Techniken in realen Projekten anwenden können, und erhalten fertige Codebeispiele.
1. Klassischer Ansatz: ThreadPoolExecutor und BlockingQueue
\nDie Standardbibliothek von Java (und Kotlin als JVM-Sprache) bietet die leistungsstarke Klasse ThreadPoolExecutor. Sie verwaltet einen Thread-Pool und verwendet eine interne blockierende Warteschlange zur Speicherung wartender Aufgaben.
Erstellen einer Warteschlange mit einer festen Anzahl von Threads
\nDer einfachste Fall ist ein Pool mit einer festen Anzahl von Threads. Alle Aufgaben, die nicht sofort ausgeführt werden können, werden in die Warteschlange LinkedBlockingQueue eingereiht.
import java.util.concurrent.Executors\nimport java.util.concurrent.TimeUnit\n\nfun main() {\n val executor = Executors.newFixedThreadPool(3)\n\n for (i in 1..10) {\n executor.submit {\n println("Aufgabe $i wird im Thread ${Thread.currentThread().name} ausgeführt")\n Thread.sleep(1000)\n }\n }\n\n executor.shutdown()\n executor.awaitTermination(1, TimeUnit.MINUTES)\n println("Alle Aufgaben abgeschlossen")\n}\n\nDieser Code demonstriert eine grundlegende Warteschlange: Aufgaben werden an den Pool gesendet, und wenn alle Threads belegt sind, warten sie in der Warteschlange.
\n\nPrioritätswarteschlange: PriorityBlockingQueue
\nManchmal ist es erforderlich, dringende Aufgaben vor anderen auszuführen. Dafür verwenden wir PriorityBlockingQueue mit einem benutzerdefinierten Comparator.
import java.util.concurrent.PriorityBlockingQueue\nimport java.util.concurrent.ThreadPoolExecutor\nimport java.util.concurrent.TimeUnit\n\ndata class PriorityTask(val priority: Int, val name: String) : Comparable<PriorityTask> {\n override fun compareTo(other: PriorityTask): Int = other.priority - this.priority\n}\n\nfun main() {\n val queue = PriorityBlockingQueue<Runnable>(10) { r1, r2 ->\n val t1 = (r1 as PriorityTaskWrapper).task\n val t2 = (r2 as PriorityTaskWrapper).task\n t1.compareTo(t2)\n }\n\n val executor = ThreadPoolExecutor(2, 4, 1, TimeUnit.SECONDS, queue)\n\n class PriorityTaskWrapper(val task: PriorityTask, val action: () -> Unit) : Runnable {\n override fun run() = action()\n }\n\n for (i in 1..5) {\n val priority = if (i % 2 == 0) 10 else 1\n executor.submit(PriorityTaskWrapper(PriorityTask(priority, "Aufgabe $i")) {\n println("Wird ausgeführt: ${PriorityTask(priority, "Aufgabe $i")}")\n Thread.sleep(500)\n })\n }\n\n executor.shutdown()\n executor.awaitTermination(1, TimeUnit.MINUTES)\n}\n\nHier werden Aufgaben mit priority = 10 früher ausgeführt als solche mit priority = 1, selbst wenn sie später hinzugefügt wurden.
2. Aufgabenwarteschlangen mit Coroutines (kotlinx.coroutines)
\nModernes Kotlin bietet Coroutines – leichtgewichtige Threads, die den Aufbau asynchroner Warteschlangen ohne direkte Thread-Verwaltung ermöglichen. Das wichtigste Werkzeug sind Channel und Dispatchers.
Einfache Warteschlange über Channel
\nChannel ist das Analogon einer blockierenden Warteschlange, jedoch für Coroutines. Es ermöglicht die sichere Übergabe von Aufgaben zwischen Coroutines.
import kotlinx.coroutines.*\nimport kotlinx.coroutines.channels.Channel\n\nsuspend fun processTas