Threads, Goroutinen und async/await in Java: Nebenläufigen Code richtig schreiben

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Nebenläufigkeit in Java: Von klassischen Threads zu Goroutinen und async/await

\n\n

Java ist eine Sprache, die von Geburt an mit mehreren Aufgaben gleichzeitig umgehen kann. Aber die Welt steht nicht still. Heute sprechen wir über Nebenläufigkeit in Java – von den guten alten Threads (Thread) über virtuelle Threads (Goroutinen aus Project Loom) bis hin zum asynchronen Ansatz mit async/await (am Beispiel von CompletableFuture).

\n\n

Wenn Sie in Java programmieren und möchten, dass Ihr Server unter Last nicht „lahmt“ und der Code lesbar bleibt, ist dieser Artikel genau das Richtige für Sie. Los geht's!

\n\n

Warum ist Nebenläufigkeit für moderne Java-Entwickler wichtig?

\n\n

Stellen Sie sich vor, Ihre Website verarbeitet 10.000 Anfragen pro Sekunde. Wenn jede Anfrage sequenziell ausgeführt wird, warten die Benutzer eine Ewigkeit. Nebenläufigkeit in Java ermöglicht es, viele Aufgaben „gleichzeitig“ auszuführen und die Prozessorressourcen effizient zu nutzen.

\n\n

Moderne Anwendungen sind nicht nur CRUD. Es sind Microservices, Datenstromverarbeitung, WebSocket, Echtzeit-Analytik. Ohne Verständnis von Multithreading in Java riskieren Sie, Code zu schreiben, der entweder mit einem OutOfMemoryError abstürzt oder sich wie eine Schnecke bewegt.

\n\n

Stufe 1: Klassische Threads (Thread) – das Fundament

\n\n

Ein Thread in Java ist die niedrigste Abstraktionsebene, um Code parallel auszuführen. Jeder Thread ist ein separater „leichter“ Prozess innerhalb des Betriebssystems.

\n\n

So sieht ein einfaches Beispiel zum Erstellen eines Threads aus:

\n\n
public class ThreadExample {\n    public static void main(String[] args) {\n        Thread thread = new Thread(() -> {\n            for (int i = 0; i < 5; i++) {\n                System.out.println("Hallo aus dem Thread: " + i);\n                try {\n                    Thread.sleep(1000);\n                } catch (InterruptedException e) {\n                    Thread.currentThread().interrupt();\n                }\n            }\n        });\n        thread.start();\n        System.out.println("Der Hauptthread arbeitet weiter");\n    }\n}
\n\n

Vorteile:

\n
    \n
  • Einfachheit der Erstellung – new Thread(() -> { ... }).start();
  • \n
  • Direkte Steuerung des Lebenszyklus.
  • \n
\n\n

Nachteile:

\n
    \n
  • Das Erstellen eines Threads ist eine teure Operation (Overhead durch Stack, Kontextwechsel).
  • \n
  • Begrenzung der Anzahl: 10.000 Threads können Ihre JVM lahmlegen.
  • \n
  • Komplexität der Synchronisation: Deadlock, Race Condition.
  • \n
\n\n

Der klassische Ansatz ist gut für kleine Aufgaben, aber für High-Load-Anwendungen ungeeignet. Genau hier kommen virtuelle Threads in Java ins Spiel.

\n\n

Stufe 2: Virtuelle Threads (Project Loom) – Goroutinen in Java

\n\n

Wenn Sie schon von Goroutinen in Go gehört haben, dann sind virtuelle Threads in Java fast dasselbe. Sie sind in Java 21 (Project Loom) erschienen und verändern die Spielregeln komplett.

\n\n

Virtuelle Threads sind „leichtgewichtige“ Threads, die von der JVM und nicht vom Betriebssystem verwaltet werden. Man kann sie millionenfach erstellen, und sie verbrauchen nur minimalen Speicher.

\n\n

Beispiel zum Erstellen eines virtuellen Threads:

\n\n
public class VirtualThreadExample {\n    public static void main(String[] args) throws InterruptedException {\n        // Erstellen von 100.000 virtuellen Threads\n        var threads = new Thread[100_000];\n        for (int i = 0; i < threads.length; i++) {\n            threads[i] = Thread.startVirtualThread(() -> {\n                // Simulation von Arbeit mit blockierendem I/O\n                try {\n                    Thread.sleep(1000);\n                } catch (InterruptedException e) {\n                    Thread.currentThread().interrupt();\n                }\n            });\n        }\n        for (Thread t : threads) {\n            t.join();\n        }\n        System.out.println("Alle virtuellen Threads sind abgeschlossen!");\n    }\n}
\n\n

Fantastisch, nicht wahr?

Blogs

Buchempfehlungen