Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Project Loom: Virtual Threads von Java 21 lösen...

Project Loom: Virtual Threads von Java 21 lösen den Knoten

Vortrag von Martin Lehmann und Rüdiger Grammes auf den IT-Tagen 2024

IT-Tage 2024, 09.–12.12.2024 | Frankfurt am MainDienstag, 10. Dezember 2024
https://www.ittage.informatik-aktuell.de/programm/2024/virtual-threads-von-java-21-loesen-den-knoten.html

Code-Beispiele auf Github: https://github.com/accso/loom

Virtual Threads von Java 21 lösen den Knoten

Bereit, den Knoten der Thread-Programmierung mit Java 21 zu entwirren? Herkömmliche Threads in Java sind teure Ressourcen, schwergewichtig in der Skalierung und blockieren beim Warten auf I/O. Virtual Threads (aus dem Project Loom, JEP 44) sind mit Java 21 produktiv verfügbar. Sie sind eine sehr leichtgewichtige Implementierung, die auch Millionen solcher Threads auf einer JVM abbilden kann. Virtual Threads ermöglichen somit eine deutlich höhere Skalierbarkeit und Effizienz bei der Verwaltung nebenläufiger Aufgaben. In diesem Vortrag verfolgen wir diesen roten Faden:

Wir erklären technische Grundlagen von Virtual Threads. Wir zeigen, wie sich Virtual Threads gegen bekannte und altbewährte Konzepte (Plattform Threads, Green Threads) abheben und wagen zudem den Vergleich mit anderen Concurrency-Ansätzen auf der JVM. Und wir werfen einen Blick auf zwei ergänzende Features des JDK: Structured Concurrency (JEP 453) und Scoped Values (JEP 446) runden Virtual Threads ab.

Martin Lehmann

December 09, 2024
Tweet

More Decks by Martin Lehmann

Other Decks in Technology

Transcript

  1. Virtual Threads von Java 21 lösen den Knoten Abstract Virtual

    Threads von Java 21 lösen den Knoten Bereit, den Knoten der Thread-Programmierung mit Java 21 zu entwirren? Herkömmliche Threads in Java sind teure Ressourcen, schwergewichtig in der Skalierung und blockieren beim Warten auf I/O. Virtual Threads (aus dem Project Loom, JEP 44) sind mit Java 21 produktiv verfügbar. Sie sind eine sehr leichtgewichtige Implementierung, die auch Millionen solcher Threads auf einer JVM abbilden kann. Virtual Threads ermöglichen somit eine deutlich höhere Skalierbarkeit und Effizienz bei der Verwaltung nebenläufiger Aufgaben. In diesem Vortrag verfolgen wir diesen roten Faden: Wir erklären technische Grundlagen von Virtual Threads. Wir zeigen, wie sich Virtual Threads gegen bekannte und altbewährte Konzepte (Plattform Threads, Green Threads) abheben und wagen zudem den Vergleich mit anderen Concurrency-Ansätzen auf der JVM. Und wir werfen einen Blick auf zwei ergänzende Features des JDK: Structured Concurrency (JEP 453) und Scoped Values (JEP 446) runden Virtual Threads ab. IT-Tage 2024, 09.–12.12.2024 | Frankfurt am Main Dienstag, 10. Dezember 2024 https://www.ittage.informatik-aktuell.de/programm/2024/virtual-threads-von-java-21-loesen-den-knoten.html
  2. Martin Lehmann Accso - Accelerated Solutions GmbH Cheftechnologe Martin Lehmann

    ist Diplom-Informatiker und arbeitet als Cheftechnologe bei der Accso - Accelerated Solutions GmbH. Seit Ende der 90er-Jahre arbeitet er als Softwarearchitekt in Individualentwicklungsprojekten für Kunden verschiedener Branchen. Er interessiert sich besonders für Software-Architektur und Entwicklungsmethodik, gerne auf der Java-Plattform. [email protected] @mrtnlhmnn.bsky.social www.linkedin.com/in/mrtnlhmnn Rüdiger Grammes Accso - Accelerated Solutions GmbH Softwarearchitekt Rüdiger Grammes arbeitet als Principal bei der Accso - Accelerated Solutions GmbH. Er beschäftigt sich seit über 20 Jahren mit Java in allen Facetten und leitet die Java-Community von Accso. [email protected] https://www.linkedin.com/in/rüdiger-grammes-26052232a
  3. IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes

    (Accso – Accelerated Solutions GmbH) 4 Einleitung, Motivation „Java Concurrency in Practice“ ist 2006 erschienen und ein Standardwerk für nebenläufige Programmierung in Java. Es behandelt weiterhin aktuelle Konzepte: • Threads • ThreadPools • Executors • Locks • …
  4. 5 Einleitung, Motivation Concurrency-Konzepte: • ForkJoinPools / Work Stealing (Java

    7) • Non-Blocking I/O (Java 7) • CompletableFutures (Java 8) Neu: Project Loom enthält … • Virtual Threads (Final in Java 21) • Structured Concurrency (Preview seit Java 21) • Scoped Values (Preview seit Java 21) IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH)
  5. 7 Wozu braucht man Virtual Threads? Klassische Threads skalieren nur

    begrenzt Threads ermöglichen nebenläufige Programmierung in Java. Klassische Threads: 1 Java-Thread = 1 OS-Thread Vorteile: • OS übernimmt Scheduling, Kontext- Switches • Preemptive Scheduling • OS reserviert einen Stack für jeden Thread OS Thread OS Thread OS Thread OS Thread Kernel Java Thread Java Thread Java Thread Java Thread Request Request Request Request Linux: Light-Weight Process IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH)
  6. 8 Wozu braucht man Virtual Threads? Klassische Threads skalieren nur

    begrenzt Threads ermöglichen nebenläufige Programmierung in Java. Klassische Threads: 1 Java-Thread = 1 OS-Thread OS-Threads sind (relativ) schwergewichtig: • Kernel-Aufruf zur Thread-Erzeugung • Verwaltung der Threads im Kernel • Zusammenhängender virtueller Speicher für max. Stack-Größe => OS-Threads skalieren nur begrenzt OS Thread OS Thread OS Thread OS Thread Kernel Java Thread Java Thread Java Thread Java Thread Request Request Request Request Linux: Light-Weight Process IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH)
  7. 9 „Async“ löst das Skalierungsproblem – mit Einfluss auf den

    Programmierstil „Async“ löst das Problem durch nicht- blockierende Operationen und eine begrenzte Anzahl an Threads. Async verlangt einen anderen Programmierstil: - Asynchrone Funktionen ohne direkten Rückgabewert - Nutzung von Promises/Futures - Kein Blockieren des Threads! Kernel Event Loop OS Thread OS Thread Evt Evt Evt Evt Evt Evt Evt Evt Evt Evt Evt Evt Evt Evt Evt Evt Evt Evt IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH)
  8. 10 Das Nachrüsten von Async führt zu aufgeblähten APIs Beispiel

    HTTPClient: Wie werden eigene APIs gestaltet? • Synchron? • Asynchron? • Beides? IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH)
  9. 11 Async: Mit dem Stack geht auch der Aufrufkontext verloren

    Die asynchron ausgeführte Methode wird nicht auf dem Stack des Aufrufers ausgeführt. Damit geht Kontextinformation z.B. bei Stacktraces verloren. a() { b() { x = IO() } } a() { b() { x = await IO() } } a a b a b IO a a b IO IOException() … b() … a() … IOException() … IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH)
  10. 12 Virtual Threads in Java: Leichtgewichtig mit gewohntem Programmierstil Mit

    Java 21 wurden Virtual Threads in Java eingeführt. Virtual Threads sind leichtgewichtige Threads, die von der JVM selbst verwaltet werden. Diese werden auf wenigen OS- Threads ausgeführt. Auf einer JVM können „problemlos“ 1Mio+ Virtual Threads parallel gestartet werden. OS Thread OS Thread Kernel Carrier Thread Carrier Thread VT VT VT VT VT VT VT VT VT VT VT VT VT VT VT VT VT VT mount IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH) mount
  11. 13 Virtual Threads in Java: Leichtgewichtig mit gewohntem Programmierstil Mit

    Java 21 wurden Virtual Threads in Java eingeführt. Virtual Threads sind leichtgewichtige Threads, die von der JVM selbst verwaltet werden. Diese werden auf wenigen OS- Threads ausgeführt. Auf einer JVM können „problemlos“ 1Mio+ Virtual Threads parallel gestartet werden. OS Thread OS Thread Kernel Carrier Thread Carrier Thread VT VT VT VT VT VT VT VT VT VT VT VT VT VT VT VT VT VT mount IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH) mount Virtual Threads besitzen einen Stack! (wird von der JVM im Heap verwaltet)
  12. 14 Virtual Threads werden weitgehend wie klassische Threads verwendet Virtual

    Threads können über die Thread-Klasse oder einen ExecutorService erzeugt werden. Ein Virtual Thread erbt von der Klasse Thread. // Virtual Thread über Thread-Klasse erzeugen Thread thread = Thread.ofVirtual().start(() -> { System.out.println("Hello Virtual Thread World!") }); System.out.println(thread.isVirtual()); // Virtual Thread über ExecutorService ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); Future task = executor.submit(() -> { System.out.println("Hello Virtual Thread World!"); }); IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH) Virtual Threads haben keine Namen, nur eine ID.
  13. 15 Virtual Threads besitzen ein kooperatives Scheduling Wer übernimmt das

    Scheduling, wenn die Threads nicht mehr vom OS verwaltet werden? Virtual Threads laufen so lange, bis sie blockieren. Bei einer blockierenden Operation löst die JVM den Virtual Thread vom OS-Thread. CPU-intensive Tasks, die nicht blockieren, sind damit nur bedingt für Virtual Threads geeignet. Als Scheduler verwendet die JVM per Default einen Fork-Join-Pool. IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH)
  14. 16 „Pinning“ – keine Freigabe des Carrier Threads trotz Blocking

    Bestimmte Fälle können dazu führen, dass ein Carrier Thread trotz einer blockierenden Operation nicht freigegeben wird. • Der blockierende Aufruf passiert in einem synchronized Block • In Fällen, in denen native Code wieder Java-Code aufruft Durch die begrenzte Zahl an Carrier Threads ein potentielles Problem! Die JVM bekommt Pinning mit und kann es loggen: -Djdk.tracePinnedThreads=short/full IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH)
  15. 17 „Pinning“ – keine Freigabe des Carrier Threads trotz Blocking

    Bestimmte Fälle können dazu führen, dass ein Carrier Thread trotz einer blockierenden Operation nicht freigegeben wird. • Der blockierende Aufruf passiert in einem synchronized Block • In Fällen, in denen native Code wieder Java-Code aufruft Durch die begrenzte Zahl an Carrier Threads ein potentielles Problem! Die JVM bekommt Pinning mit und kann es loggen: -Djdk.tracePinnedThreads=short/full JEP 491 soll dieses Problem lösen! (geplant für Java 24) IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH)
  16. 18 Virtual Threads sind kein 1:1 Ersatz für klassische Threads

    Virtual Threads sind „billig“ – keine Thread Pools verwenden, sondern einfach neue Threads erzeugen Virtual Threads sind kooperativ – besser für I/O-bound Tasks als für CPU-bound Tasks Gefahr durch Pinning, auch unbewusst durch Einsatz von Libraries Nicht einfach bestehende Threads durch Virtual Threads ersetzen! IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH) Virtual Threads sind nicht per se schneller (höchstens bei der Erzeugung)
  17. 19 Die Skalierungsversprechen von Virtual Threads sind mit Vorsicht zu

    genießen IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH) Auch 1 Mio. Virtual Threads funktionieren nicht unbedingt und skalieren nicht beliebig! • Bei Virtual Threads mit hoher Rechenlast • Bei Virtual Threads mit großen Stacks • Das Betriebssystem hat auch I/O –Limits (z.B. Disk I/O) → Ziel ist die optimale Ausnutzung der OS-Ressourcen.
  18. Beispiel Für eine BigBand benötigen wir: 1. Wecke alle Musiker

    auf 2. Suche alle Instrumente zusammen 3. Hole alle Ergebnisse 4. Baue Bigband auf 5. Paralleles Teile & Herrsche: Future → StructuredConcurrency IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH) BigBandBuilder Main Thread get get 21 Thread 2 fork Search Instru- ments Thread 1 fork Wake Up Musicians Wir teilen eine große Aufgabe in kleinere Teile und parallelisieren dabei die Ausführung.
  19. 22 Future (seit Java 1.5) - Probleme (1) Joins im

    Programmcode unschön, zu viele Freiheitsgrade, Fehlerhandling nicht trivial (2) Nebenläufige Struktur (Tasks) spiegelt sich nicht (gut) im Programmcode wider (3) Ergebnisse aller Tasks werden benötigt? → Bricht ein Task mit Fehler ab, laufen die anderen unnötigerweise weiter (4) Ergebnisse nur eines Tasks wird benötigt? „Fan out“ → Alle Tasks laufen bis zum Ende, obwohl erstes Ergebnis bereits ausreicht IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH) StructuredConcurrency (Preview) Angelehnt an Strukturierte Programmierung • StructuredTaskScope, Scope und Tasks mit join (auch mit Timeout) • Zu (3) ShutdownOnFailure → bricht ein Task mit Exception ab, werden alle beendet • Zu (4) ShutdownOnSuccess → endet ein Task, werden alle beendet • Tasks laufen auf Virtual Threads, man kann eigene ThreadFactory mitgeben • 5th Preview bringt: Joiner, eigene Strategien für Tasks / Joiner Potentielle Ressourcenverschwendung: https://openjdk.org/jeps/8340343 Paralleles Teile & Herrsche: Future → StructuredConcurrency
  20. 24 Ein Kontext per Thread: ThreadLocal → ScopedValue Ziel: Kontext

    per Thread (v.a. im Thread-per- Request-Modell sehr nützlich) IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH) Fachlicher Kontext, z.B. Mandant oder Correlation-Id Technischer Kontext, z.B. User-Login Framework MyApp Request 1 Request 2 MyApp Setzt Kontext per Thread: Corr-ID, Region, User Main Thread Thread 2 Setzt Kontext per Thread: Corr-ID, Region, User Thread 1
  21. 25 ThreadLocal (seit Java 1.2) – Probleme (1) TL lebt

    so lange wie der Thread • Inhalt muss explizit gelöscht werden (remove) • Potentielles Memory/Security Leak, v.a. bei Thread-Pools (2) TL ist mutable, kann überall gesetzt werden • Auch Thread („MyApp“) kann set aufrufen • Potentieller Spaghetti-Code, wenn damit Daten hin-und-her-kopiert werden (3) Teuer • wird in Child-Threads kopiert IT-Tage 2024, 10. Dezember 2024 Martin Lehmann, Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH) ScopedValue (Preview) ThreadLocal wird nicht ersetzt / deprecated • Klarer Scope, leichtgewichtig • Zu (1) Werden automatisch gelöscht am Ende ihres Scopes • Zu (2) Werden nur einmal gesetzt, haben klar definierte Richtung „Framework → MyApp“, also Caller→Callee • Nested Scope möglich • ScopedValue wird an Child-Threads vererbt (nicht: kopiert) Ein Kontext per Thread: ThreadLocal → ScopedValue
  22. 27 Unser Fazit IT-Tage 2024, 10. Dezember 2024 Martin Lehmann,

    Dr. Rüdiger Grammes (Accso – Accelerated Solutions GmbH) Virtual Threads • Java 21 (LTS) • Fokus auf Ressourcen- Optimierung • Ist nicht per se schneller • Hat ebenfalls Limitierungen → Gezielt einsetzen! Structured Concurrency • Java 24 (3/25), noch Preview • Bessere Abbildung der Task-Strukturen • Klarer Scope • Hilft für Fehler / Beendigung (alle, einer, keine, viele, custom, …) • Observability-Tools, z.B. ThreadDump, zeigen die Hierarchie ScopedValues • Java 24 (3/25), noch Preview • Klarere API als ThreadLocal • Vermeidet Fehler • Aber nichts substantiell Neues • In Kombination mit Struct. Concurrency einsetzen
  23. Accso – Accelerated Solutions GmbH T | +49 6151 13029-0

    E | [email protected] @ | www.accso.de Hilpertstraße 12 | 64295 Darmstadt Rahmhofstraße 2 | 60313 Frankfurt a. M. Im Mediapark 6a | 50670 Köln Balanstraße 55 | 81541 München Clocktower, 302 | CV&A Waterfront, Cape Town 8002, ZA https://accso.de/wissen/publikationen https://speakerdeck.com/mrtnlhmnn https://github.com/accso/loom