© Marwan Abu-Khalil Page 1 Virtual Threads in Java Scalability and Performance in a new Dimension Marwan Abu-Khalil 2025
© Marwan Abu-Khalil Contact seminar@abu-khalil.de Marwan Abu-Khalil Senior Software Architect Siemens AG Berlin, Germany www.linkedin.com/in/marwan-abu-khalil Marwan Abu-Khalil Page 2 Seminars § Technische Akademie Esslingen Software Architecture Introduction § iX Workshops, Heise Akademie Software-Architecture Introduction Conference Talks § W-JAX, Munich November 2025: Virtual Threads Workshop § JAX, Mainz Mai 2025: Reactive Streams Workshop Publication on Virtual Threads § Java Spektrum, 2.2025 Virtual Threads in Java: Performance und Skalierbarkeit in neuer Dimension
© Marwan Abu-Khalil 1 Understanding Virtual Threads 2 Performance & Scalability 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features 6 Behind the Scenes Agenda Page 4
© Marwan Abu-Khalil 1 Understanding Virtual Threads o Motivation o What is a thread? o Mechanics of virtual threads o Benefits of virtual threads o API and usage of virtual threads 2 Performance & Scalability 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features 6 Behind the Scenes Agenda Page 5 Ask your questions in the chat
© Marwan Abu-Khalil § Architecture options for concurrent systems o Reality: (simple + synchronous) OR (complex + asynchronous) o Wish: simple + asynchronous § Typical server application: Blocking calls o Blocked threads: Expensive resource wasted § Idea of virtual threads o OS thread released during blocking call Motivation: Scalable Server Applications Page 6 Thread per request: Many clients => many blocking threads within server Not Scalable with classic Platform-Threads
© Marwan Abu-Khalil § Thread in general o Path of execution (instruction pointer) o Scheduled and realized by operating system o Memory for stack and CPU-register set § Classic Java Thread is expensive 1. Stack (Memory) 2. OS-Scheduling (CPU) What is a (classic) Thread? Page 7 Number of threads => coexisting simultaneously is limited!
© Marwan Abu-Khalil § Virtual Thread M:N Platform-Thread (cheap) o Realized in Java / JVM o Scheduling in Java / JVM (fast) o Temporarily executed by a platform thread o Stack: dynamic § Platform-Thread 1:1 OS-Thread (expensive) o Java Thread: Wrapper around OS-Thread o Scheduled by OS o “Carrier” of Virtual Thread o Stack: static § OS thread (expensive) o Realized by OS o Scheduled by OS Layers and Terms: Virtual-Thread, Platform-Thread (Carrier), OS-Thread Page 8
© Marwan Abu-Khalil § Synchronous programming model: Like classic threads § Asynchronous execution: When virtual thread blocks, underlying OS thread gets released § High scalability: Hundreds of thousands … millions Idea of Virtual Threads: Few platform threads run many virtual threads Page 9 Pool of few expensive platform threads: Executes virtual threads
© Marwan Abu-Khalil 1. Memory: Static Stack vs. Dynamic Stack § Platform Thread: "expensive" in terms of memory o Fixed-size stack o Assigned at start() § Virtual Thread: cheap in terms of memory o Dynamic Stack of Stack Chunks o Stack chunks allocated as needed at runtime o Swap-In / Swap-Out at mounting / unmounting Virtual Threads: Cheap compared to platform threads Page 10 Risk: Large dynamic stack => advantage gets lost! 2. CPU: Scheduling in “User Mode” § Platform Thread: OS-Scheduling: expensive, slow § Virtual Thread: Scheduling in JVM, without OS, fast Consequence: Non-preemptive scheduling
© Marwan Abu-Khalil § Programming model identical to classic Java threads § Platform thread released as soon as virtual thread blocks Key Feature: Automatic release of platform thread in case of blocking Page 11 // Start Thread virtualThread = Thread.startVirtualThread(() -> { System.out.println("Virtual Thread id: " + Thread.currentThread().threadId()); }); // Wait virtualThread.join();
© Marwan Abu-Khalil Dynamics of Blocking & Releasing Page 12 Non-Preemptive Scheduling!
© Marwan Abu-Khalil Synchronous vs. asynchronous programming Page 14 Flux.range(1, 8) // DB Access: 1 Sec blocking .map( and -> readFromDatabase(i)) // Stage decoupling .publishOn(Schedulers.parallel()) .map( list -> computeCPUData(list)) .publishOn(Schedulers.parallel()) .subscribe( list->showInUI(cpuList)); Asynchronous Execution: Reactive Streams for(int i = 1 ; i <= 8; ++i) { final int inputValue = i; Thread thread = new Thread(() ->{ // DB Access: 1 Sec blocking var databaseList = readFromDatabase(inputValue); // CPU: 1 Sec computing var cpuList = computeCPUData(databaseList); // UI showInUI(cpuList); }); thread.start(); } Synchronous: Thread per Request for(int i = 1 ; i <= 8; ++i) { final int arg = i; // Stage 1: DB Access CompletableFuture.supplyAsync(()->readFromDatabase(arg)) // Callback Stage 2: CPU Computation .thenApplyAsync((List<Integer> dbResultSet) -> { return computeCPUData(dbResultSet); }) // Callback Stage 3: UI Rendering .thenAcceptAsync((cpuData) ->{ showInUI(cpuData); }); } Asynchronous Programming: CompletableFutures Simple but inefficient Efficient, but own programming model Complex Programming
© Marwan Abu-Khalil Goal § Simple sequential programming o Like classic threads § Efficient asynchronous execution o Like Reactive Streams Mechanism o OS thread: Release in case of blocking o Asynchrony: Managed automatically Technological background o Mapping Virtual -> Platform-Thread o Operating System asynchronous IO o Non-preemtive scheduling Virtual Threads combine the best of both worlds: Sequential programming + asynchronous execution Page 15
© Marwan Abu-Khalil § 1. Why is a platform thread expensive? o Stack: Memory o OS-Scheduling: CPU § 2. Why is a virtual thread cheap? o Dynamic stack o JVM scheduling o Executed by platform thread § 3. What happens when a virtual thread calls a blocking OS operation? o Carrier thread released o Carrier executes other virtual thread o After blocking call returns: Virtual thread runnable Recap Page 23
© Marwan Abu-Khalil What happens when a new virtual thread is created? § Instance of virtual thread is created § New virtual thread mapped to platform thread from pool § Associated platform thread runs virtual thread § Platform thread called "carrier thread" API and usage of virtual threads Page 26
© Marwan Abu-Khalil 1. Class Thread 2. ExecutorService (Pool) 3. ThreadBuilder Virtual-Thread extends Thread => Key for simple migration Ways to start a Virtual Thread Page 27 // Start: Class Thread Thread virtualThread = Thread.startVirtualThread(() ->{}); // Start: ExecutorService Executors.newVirtualThreadPerTaskExecutor().submit(() -> {}); // Start: ThreadBuilder Thread.ofVirtual().name("MyVirtualThread").unstarted(() -> {}).start();
© Marwan Abu-Khalil § ExecutorService creation: newVirtualThreadPerTaskExecutor() § Virtual threads never reused § Virtual thread performs one single task, then dies! § Future: Obtain result asynchronously Option 2: Executor Service Page 29 // Pool Interface: ExecutorService ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); // Start Future<?> threadResult = executor.submit(() -> { System.out.println("Virtual Thread via Executor ” + Thread.currentThread()); }); // Wait threadResult.get();
© Marwan Abu-Khalil § Virtual threads can be instantiated at ”unlimited” amount o Since they are extremely "cheap" § Reuse is pointless o Virtual threads should never be pooled, they are too cheap o Only platform threads should be pooled (e.g. by ExecutorService) § Beware of "deep stacks" o Performance advantage may be lost o Long running tasks are not good candidates for virtual threads Important Guidlines for using Virtual Threads Page 33
© Marwan Abu-Khalil 1 Understanding Virtual Threads 2 Performance & Scalability o Is a Virtual Thread faster? o How can more Concurrency increase Performance? o Examples for Scalability and Performance 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features 6 Behind the Scenes Agenda Page 34 Ask your questions in the chat
© Marwan Abu-Khalil NO! Computing speed on CPU is identical!!! § How can virtual threads increase performance? § Virtual threads "only" increase number of simultaneously blocking calls => More simultaneous tasks => More clients at the same time => Higher scalability => Higher throughput => Overall performance improves Is a Virtual Thread faster than a Platform Thread??? Page 35
© Marwan Abu-Khalil § Little’s law (John Little, 1954) o Theoretic background for performance increase o Increased concurrency with constant response time implies higher throughput § Modern OS o Can handle many (thousands) simultaneous threads o BUT: Application shoud use few, because they are expensive § Thread Pools provide efficency o Pool size according to number of CPU-cores o Threads kept busy Why is scalabilty a challenge with classic threads? …and how can we gain performance? Page 36 Little’s Law Concurrency => Throughput => Performance!
© Marwan Abu-Khalil More simultaneous Clients through Thread Virtualization Page 37 Classic Thread Model Expensive platform threads block during I/O => Few concurrent clients Virtual Thread Model Platform threads always running => Many concurrent clients
© Marwan Abu-Khalil § 10,000 Platform-Threads start o After 4000 threads crash: OutOfMemoryError § Alternative: Start 10,000 virtual threads o Runs smoothly § Crucial: blocking OS call (e.g.sleep()) § Effect of Virtual Threads Architecture o Number of parallel tasks massively increased o Little's Law: Throughput increased Example Scalability Page 39 Platform Threads: Crash Virtual Threads: Scale Real limit depends on OS, HW and configuration
© Marwan Abu-Khalil § Platform threads start § sleep(): Blocking call § After 4000 threads are started: OutOfMemoryError 10,000 Platform Threads: Crash Page 40 for(int i = 0; i < 1_000_0; ++i) { final int cnt = i; // Launch Platform Thread Thread thread = new Thread(()->{ System.out.println("New OS Thread"+ cnt); // Sleep (blocking call) Thread.sleep(1000); // Exception handling omitted }); thread.start(); } 2 1 Adapt thread count and sleep time to your platform for experiments 3
© Marwan Abu-Khalil 10,000 Virtual-Threads: Start easily Page 41 for(int i = 0; i < 10_000; ++i) { final int cnt = i; // Starting virtual thread Thread.startVirtualThread(()->{ System.out.println(”New virtual Thread: " + cnt); sleep(1000); }); } Where does this help? Scalable Server
© Marwan Abu-Khalil Performance Example: Increase through virtual threads factor 10!! Page 43 // Variant 1 Platform Threads: 10 seconds, Pool of 1000 Threads //ExecutorService pool = Executors.newFixedThreadPool(1000); // Variant 2 Virtual Threads: 1 second ExecutorService pool = Executors.newVirtualThreadPerTaskExecutor(); long start = System.currentTimeMillis(); for(int i = 0 ; i <= 10_000; ++i) { final int loop_cnt = i; pool.submit(() -> { // Blocking call (exception handling omitted) Thread.sleep(1000); System.out.println("Job " + loop_cnt + " woke up " + (System.currentTimeMillis() - start) / 1000 + " Seconds "); } } One second with 10,000 virtual threads 10 seconds with 1,000 platform threads More simultaneous tasks => Better overall performance
© Marwan Abu-Khalil Positive § Higher scalability compared to platform threads § Performance can be massively improved by high scalability (Little's Law) Conclusion on Performance and Scalability of Virtual Threads Page 51 Negative § Blocking calls necessary to profit form virtual threads § Not all architectures, use cases, and systems can benefit from virtual thread migration
© Marwan Abu-Khalil 1 Understanding Virtual Threads 2 Performance & Scalability 3 Architecture and Blocking Calls o Rules for Migration o Relevance of blocking Calls o Examples for Scheduling Behavior 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features 6 Behind the Scenes Agenda Page 52 Ask your questions in the chat
© Marwan Abu-Khalil 1. Performance limited by amout of available threads o Application could run faster with more threads o Rationale: Virtual threads only add concurrency, not paralleleism, not computing power 2. Significant time spent in blocking OS-calls („IO-Bound“) o Rationale: Virtual threads change system behaviour only during blocking OS-calls Two necessary Pre-Conditions for Performance Gain through Migration to Virtual Threads Page 53 CPU-bound Apps DO NOT BENEFIT!!! except in rare corner cases where context switching is a bottleneck see Quarkus Docu: https://quarkus.io/guides/virtual-threads#cpu-bound
© Marwan Abu-Khalil § Typical server application o Significant amount of time: Blocking calls o E.g. database, internal and external services § Thread per Request o Simple to program o Scales only to thread limit of OS § Idea of Virtual Threads o Release OS thread on blocking call o Inside the JVM process: Lock.lock(), Thread.sleep()... o Outside, I/O: Socket, File Access... Relevance and handling of blocking calls (recap) Page 54
© Marwan Abu-Khalil § A lot of virtual threads wish to execute sleep() § Single Platform Thread: Executes all virtual threads one at a time § All virtual threads block in sleep(): transferred to unmouted state § sleep() call returns: virtual thread is runnable again Example: Many virtual threads call sleep() at the same time Page 57
© Marwan Abu-Khalil § Many (1000) Virtual Threads o Start o Each calls sleep() § Few (8) Platform Threads o Execute 1000 Virtual Threads Output shows: Many virtual threads executed by a few platform threads Page 58 for(int i = 0; i < 1000; ++i) { final int cnt = i; Thread.startVirtualThread(() ->{ System.out.println("Virtual Thread Nr. " + cnt + " " + Thread.currentThread()); // Blocking call releases Carrier-Thread sleep(1000); }); } 1000 Virtual Threads 8 Platform Threads
© Marwan Abu-Khalil Scheduler Dynamics: Many Virtual Threads call sleep()
© Marwan Abu-Khalil Scenario: Queue of limited size § Many Virtual Threads call take(): blocking § Few Virtual Threads call put(): blocking § Executed by limited size Platform Thread Pool Example: Producer-Consumer with Blocking Queue Page 66 Comparison: Fork-Join-Tasks § May deadlock in queuing scenario § Do not handle blocking efficiently Behavior § Carrier released on blocking take() and put() § All threads run smoothly, no blocking
© Marwan Abu-Khalil § 10 virtual threads on 8-core computer, array with 10 slots § Each thread counts up counter in array infinitely § Result: only the first 8 slots are accessed, as only 8 virtual threads run actually § Platform threads instead: All fields in array are incremented Example: Missing preemption changes program semantics Page 69 long[] numbers = new long[10]; // 10 Virtual Threads: // Only 8 array slots processed on 8-Core CPU ExecutorService pool = Executors.newVirtualThreadPerTaskExecutor(); for(int i = 0 ; i < 10; ++i) { final int j = i; pool.execute(() ->{ while(true) { numbers[j]+=1; } }); } sleep(1000); System.out.println(Arrays.toString(numbers)); Rare corner case….
© Marwan Abu-Khalil Virtual threads characteristics § Reuse is pointless o Virtual threads never pooled! o Only platform threads pooled (ExecutorService) § Beware of "deep stacks” o Performance advantage may vanish § No Preemption o Application semantics can change Rules for the use of Virtual Threads and for Migration Recap / Summary Page 71 Migration requires two Pre-Conditions 1. Performance limited by amount of available threads 2. Significant time spent in blocking OS-calls
© Marwan Abu-Khalil 1 Understanding Virtual Threads 2 Performance & Scalability 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach o Reactive Streams comparison o JDK Alternatives: Fork-Join, Parallel Streams 5 Emerging Language Features 6 Behind the Scenes Agenda Page 91 Ask your questions in the chat
© Marwan Abu-Khalil Discussions between Reactive Streams and Virtual Threads Advocates § Arguments of virtual thread community (e.g. Brian Goetz) o Reactive streams don't fit well into Java Platform o Unit of application's concurrency is pipeline stage o Unit of the platform's concurrency is thread o Tools, stack traces, profilers, debuggers not well usable o "Foreign" programming model: without support in Java language / platform See https://www.infoq.com/articles/java-virtual-threads/ „What About Reactive“ § Arguments of ReacitveStreams community (e.g. Thomasz Nurkiewitz) o Only benefit of virtual threads programming model: easy asynchrony o Other Reactive Streams features missing: Backpressure, Change Propagation, Composability See: https://www.infoq.com/presentations/loom-java-concurrency/ Reactive Streams Comparison Page 93 Flux.range(1, 8) // DB Access: 1 Sec blocking .map( and -> readFromDatabase(i)) // Stage decoupling .publishOn(Schedulers.parallel()) .map( list -> computeCPUData(list)) .publishOn(Schedulers.parallel()) .subscribe( list->showInUI(cpuList)); Reactive Streams Example
© Marwan Abu-Khalil Virtual Threads § Make IO-bound applications scalable See: Brian Getz, Virtual Threads: new Foundations for Java High Scale Applications https://www.infoq.com/articles/java-virtual-threads/ ForkJoin and ParallelStreams § Ideal for CPU-bound applications o Many asynchronous tasks run on top of few threads § Not suitable for IO bound applications o Blocking OS call not handled well o Block underlying pool thread o Risk: Deadlock, or alternatively high memory consumption if pool grows Comparison Virtual-Threads vs. Fork-Join-Tasks & Parallel-Streams Page 94 IO-bound optimized CPU-bound optimized Fork Join Tasks Tech-Stack !"#A%C"'( F*+A%F#,, FJ#,*.%/""0 1/O 1/O P4%45J,.S0,# /*#*00,0T4U#,*9+ !"#$B&'(F*+', -./&(.$0*'"-1O#.-"+-, 1"( Virtual-Thread blocking call handling:
© Marwan Abu-Khalil § 2 Virtual Threads run and call put() § Queue full, put() blocks V-T 2 § Carrier thread P-T 2 is freed § P-T 2 now executes V-T 3 § take() frees space in the queue § V-T 2 unblocking § but has no carrier yet Blocking Queue with Virtual Threads Scenario Page 95
© Marwan Abu-Khalil § Fork-Join-Tasks o Blocking-Queue: Deadlock § put() blocks when queue full § ForkJoinTasks block Pool-Threads § No more pool threads § No ForkJoinTask runs for take() What fork-join tasks can't do that virtual threads can: e.g. producer-consumer with blocking queue Page 96
© Marwan Abu-Khalil Technology selection according to functional and non fuctional properties Page 103 Usecase Virtual Thread Platform Thread Fork-Join-Task Parallel- Stream Reactive- Stream Blocking-IO Yes perfect use-case Yes No Blocks Pool Thread No Blocks Pool Thread Yes Asynchrony System Architecture Structure Yes But focus on server scalabilty Yes Perfect use case No No blocking IO handling No More design level, no blocking IO Yes Many subscribers back-pressure Recursive Algorithm Yes Cheap parallelsim Risk: No preemption Probably not Caution: Memory requirements Yes Perfect Use-Case No Recursion not feasible within pipeline Probably not Focus: distributed concurrent system Pipeline Data Processing Probably not No API support Probably not No API support No No blocking Yes Perfect use-case Yes not primarily for parallelizing pipeline Lots of data infinite streams No Short running Yes Long running No short running No Cannot be partitioned efficiently Yes Perfect use-case API
© Marwan Abu-Khalil 1 Understanding Virtual Threads 2 Performance & Scalability 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features o Structured Concurrency o Scoped Values 6 Behind the Scenes Agenda Page 104 Ask your questions in the chat
© Marwan Abu-Khalil § Goals o Handle group of virtual threads as single unit o Eliminate concurrent programming risks regarding cancellation and shutdown § Central idea o Combine parallel tasks into a "scope" that succeed or fail together o One thread throws exception: Full “scope” exited § Constructs o StructuredTaskScope: Combines multiple virtual threads into one unit o Subtask<String> subTask1 = scope.fork(() -> {...}): fork starts new Virtual Thread o scope.join(): Waits for all threads in the scope o scope.throwIfFailed(); Terminates scope by an exception when a thread throws errors o StructuredTaskScoped.Joiner: Configures join()-behavioir, e.g. anySuccessfulResultOrThrow() / awaitAll() / awaitAllSuccessfulOrThrow(), https://openjdk.org/jeps/505 (for Java 25) https://openjdk.org/jeps/480 (for Java 23) Structured Concrurency JEP 480, 505, Preview Page 105 Java 25 / Java 23 differences, e.g: public static <T> StructuredTaskScope<T, Void> open()
© Marwan Abu-Khalil Structured Concurrency Example (Java 23 Version) Page 106 try(var scope = new StructuredTaskScope.ShutdownOnFailure()){ // Start Subtask Subtask<String> subTask1 = scope.fork(() -> { System.out.println("Task 1 called in " + Thread.currentThread()); return "Hello"; }); // Start Subtask Subtask<String> subTask2 = scope.fork(() -> { for(int i = 0; i < 1000; ++i) { System.out.println("Task 2 loop: " + i +" called in " + Thread.currentThread()); } return ”World"; }); scope.join(); scope.throwIfFailed(); System.out.println(subTask1.get()); System.out.println(subTask2.get()); } Two threads handled as one singe unit wait for all! propagate failures common “scope” bundles virtual threads together
© Marwan Abu-Khalil § Idea o ThreadLocal variables optimized for use with virtual threads o Immutable o Cheap o Shared by a hierarchy of virtual threads in a scope (StructuredTaskScope) § Elements o Declaration static final ScopedValue<... > V = ScopedValue.newInstance(); o Setting the value ScopedValue.where(V, <value>) o Binding to lambda expression ScopedValue.run(() -> { ... V.get() ... call methods ... }); o Accessing the value V.get() https://openjdk.org/jeps/487 Scoped Values JEP 487, Preview Page 108
© Marwan Abu-Khalil Scoped Values Example Page 109 Declaring Scoped Value static ScopedValue<String> SCOPED_VALUE_EXAMPLE = ScopedValue.newInstance(); Thread virtThread1 = Thread.startVirtualThread(() -> { Bind scoped value with where() and define scope with run() ScopedValue.where(SCOPED_VALUE_EXAMPLE, "Hallo").run(() -> { String valueinThread = SCOPED_VALUE_EXAMPLE.get(); System.out.println("Thread 1: " + valueinThread); }); }); Thread virtThread2 = Thread.startVirtualThread(() -> { Different value in another scope ScopedValue.where(SCOPED_VALUE_EXAMPLE, "GutenTag").run(() -> { String valueinThread = SCOPED_VALUE_EXAMPLE.get(); System.out.println("Thread 2: " + valueinThread); }); }); single instance Assign value for thread 1 other value for thread 2 different outputs Core feature: Anywhere in the code available without argument
© Marwan Abu-Khalil 1 Understanding Virtual Threads 2 Performance & Scalability 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features 6 Behind the Scenes o JVM Virtual Threads Architecture o Consequences for Application Design Agenda Page 110 Ask your questions in the chat
© Marwan Abu-Khalil 1. Blocking call: Carrier Thread released § M:N Mapping: Virtual thread run by several platform threads § New carrier after blocking call 2. Dynamic Stack § Stack can grow and shrink (StackChunk objects, lazy-loading) § Mounting / unmounting: Stack-frames copied from carrier's stack to heap (& vice versa) 3. Continuations § Virtual threads are realized as “continuations” § “one shot delimited continuations” theoretic concept behind 4. User Mode Scheduling § No preemption: A virtual thread runs to completion Architecture of virtual threads = > Consequences for App Design and Behavior Page 111 Changed program semantics, e.g. starvation Cheap scheduling Beware of deep stacks Memory saving Only IO-bound apps benefit Performance optimization Easy migration Automatic asynchrony
© Marwan Abu-Khalil Conclusion on Virtual Threads Page 114 Positive § Extremely highly scalable o Many thousands of simultaneous tasks § Massive performance boost possible o Throughput o Little’s Law § Saved resources o Memory and CPU o Platform Threads § Simple programming model o Like classic threads o Easy migration o Sequential programming, asych. execution Carefully consider before migration § Only effective with significant blocking time o Blocking time per client call relevant o Only for IO bound applications o No benefit for computationally intensive applications § High degree of concurrency required o Unreachable with platform threads o Thousands, possibly millions § Semantic change possible (rare case!) o No preemption
© Marwan Abu-Khalil 1 Understanding Virtual Threads 2 Performance & Scalability 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features 6 Behind the Scenes Agenda in Retrospect Page 115
© Marwan Abu-Khalil - Oracle Java Core Libraries Documentation: https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html - JEP Virtual Threads https://openjdk.org/jeps/425 and https://openjdk.org/jeps/444 - JEP Structured Concurrency: https://openjdk.org/jeps/453, https://openjdk.org/jeps/505 - Brian Goetz, 2022: New Foundations for Java High Scale Applications https://www.infoq.com/articles/java- virtual-threads/ - Michael Inden, 2025: Java 21 LTS bis 24 -- Coole neue Java-Features: Modernes Java leicht gemacht https://amzn.eu/d/2FrSinA - Sven Woltmann, 2022, nice little examples: https://www.happycoders.eu/de/java/virtual-threads/ - Nicolai Parlog, Oracle, 2022: https://blogs.oracle.com/javamagazine/post/java-loom-virtual-threads-platform-threads - Lutz Hühnken, entwickler.de 2020 https://entwickler.de/java/blick-in-die-fernere-zukunft - Reinald Menge-Sonntag, heise online 2022: https://www.heise.de/news/Java-19-verbessert-die-Nebenlaeufigkeit-mit-virtuellen- Threads-aus-Project-Loom-7269453.html - Ron Presler, QCon 2019: https://www.infoq.com/presentations/continuations-java/ - Thomasz Nurkiewitz, QCon 2022: https://www.infoq.com/presentations/loom-java-concurrency/ - Ricardo Cardin, 2023, good Examples about Threadpool and Scheduling: https://blog.rockthejvm.com/ultimate- guide-to-java-virtual-threads/#3-how-to-create-a-virtual-thread - Marwan Abu-Khalil, 2025 , Virtual Threads in Java: Performance und Skalierbarkeit in neuer Dimension, https://www.sigs.de/artikel/virtual-threads-in-java-performance-und-skalierbarkeit-in-neuer-dimension/ Literature and web links (some are in German, but still great!) Page 116
© Marwan Abu-Khalil Contact seminar@abu-khalil.de Marwan Abu-Khalil Senior Software Architect Siemens AG Berlin, Germany www.linkedin.com/in/marwan-abu-khalil Marwan Abu-Khalil Page 117 Seminars § Technische Akademie Esslingen Software Architecture Introduction § iX Workshops, Heise Akademie Software-Architecture Introduction Conference Talks § W-JAX, Munich November 2025: Virtual Threads Workshop § JAX, Mainz Mai 2025: Reactive Streams Workshop Publication on Virtual Threads § Java Spektrum, 2.2025 Virtual Threads in Java: Performance und Skalierbarkeit in neuer Dimension
© Marwan Abu-Khalil Page 118 Q&A Ask your QUESTIONS in the chat!

Virtual Threads in Java: A New Dimension of Scalability and Performance

  • 1.
    © Marwan Abu-Khalil Page1 Virtual Threads in Java Scalability and Performance in a new Dimension Marwan Abu-Khalil 2025
  • 2.
    © Marwan Abu-Khalil Contact seminar@abu-khalil.de MarwanAbu-Khalil Senior Software Architect Siemens AG Berlin, Germany www.linkedin.com/in/marwan-abu-khalil Marwan Abu-Khalil Page 2 Seminars § Technische Akademie Esslingen Software Architecture Introduction § iX Workshops, Heise Akademie Software-Architecture Introduction Conference Talks § W-JAX, Munich November 2025: Virtual Threads Workshop § JAX, Mainz Mai 2025: Reactive Streams Workshop Publication on Virtual Threads § Java Spektrum, 2.2025 Virtual Threads in Java: Performance und Skalierbarkeit in neuer Dimension
  • 3.
    © Marwan Abu-Khalil 1Understanding Virtual Threads 2 Performance & Scalability 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features 6 Behind the Scenes Agenda Page 4
  • 4.
    © Marwan Abu-Khalil 1Understanding Virtual Threads o Motivation o What is a thread? o Mechanics of virtual threads o Benefits of virtual threads o API and usage of virtual threads 2 Performance & Scalability 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features 6 Behind the Scenes Agenda Page 5 Ask your questions in the chat
  • 5.
    © Marwan Abu-Khalil §Architecture options for concurrent systems o Reality: (simple + synchronous) OR (complex + asynchronous) o Wish: simple + asynchronous § Typical server application: Blocking calls o Blocked threads: Expensive resource wasted § Idea of virtual threads o OS thread released during blocking call Motivation: Scalable Server Applications Page 6 Thread per request: Many clients => many blocking threads within server Not Scalable with classic Platform-Threads
  • 6.
    © Marwan Abu-Khalil §Thread in general o Path of execution (instruction pointer) o Scheduled and realized by operating system o Memory for stack and CPU-register set § Classic Java Thread is expensive 1. Stack (Memory) 2. OS-Scheduling (CPU) What is a (classic) Thread? Page 7 Number of threads => coexisting simultaneously is limited!
  • 7.
    © Marwan Abu-Khalil §Virtual Thread M:N Platform-Thread (cheap) o Realized in Java / JVM o Scheduling in Java / JVM (fast) o Temporarily executed by a platform thread o Stack: dynamic § Platform-Thread 1:1 OS-Thread (expensive) o Java Thread: Wrapper around OS-Thread o Scheduled by OS o “Carrier” of Virtual Thread o Stack: static § OS thread (expensive) o Realized by OS o Scheduled by OS Layers and Terms: Virtual-Thread, Platform-Thread (Carrier), OS-Thread Page 8
  • 8.
    © Marwan Abu-Khalil §Synchronous programming model: Like classic threads § Asynchronous execution: When virtual thread blocks, underlying OS thread gets released § High scalability: Hundreds of thousands … millions Idea of Virtual Threads: Few platform threads run many virtual threads Page 9 Pool of few expensive platform threads: Executes virtual threads
  • 9.
    © Marwan Abu-Khalil 1.Memory: Static Stack vs. Dynamic Stack § Platform Thread: "expensive" in terms of memory o Fixed-size stack o Assigned at start() § Virtual Thread: cheap in terms of memory o Dynamic Stack of Stack Chunks o Stack chunks allocated as needed at runtime o Swap-In / Swap-Out at mounting / unmounting Virtual Threads: Cheap compared to platform threads Page 10 Risk: Large dynamic stack => advantage gets lost! 2. CPU: Scheduling in “User Mode” § Platform Thread: OS-Scheduling: expensive, slow § Virtual Thread: Scheduling in JVM, without OS, fast Consequence: Non-preemptive scheduling
  • 10.
    © Marwan Abu-Khalil §Programming model identical to classic Java threads § Platform thread released as soon as virtual thread blocks Key Feature: Automatic release of platform thread in case of blocking Page 11 // Start Thread virtualThread = Thread.startVirtualThread(() -> { System.out.println("Virtual Thread id: " + Thread.currentThread().threadId()); }); // Wait virtualThread.join();
  • 11.
    © Marwan Abu-Khalil Dynamicsof Blocking & Releasing Page 12 Non-Preemptive Scheduling!
  • 12.
    © Marwan Abu-Khalil Synchronousvs. asynchronous programming Page 14 Flux.range(1, 8) // DB Access: 1 Sec blocking .map( and -> readFromDatabase(i)) // Stage decoupling .publishOn(Schedulers.parallel()) .map( list -> computeCPUData(list)) .publishOn(Schedulers.parallel()) .subscribe( list->showInUI(cpuList)); Asynchronous Execution: Reactive Streams for(int i = 1 ; i <= 8; ++i) { final int inputValue = i; Thread thread = new Thread(() ->{ // DB Access: 1 Sec blocking var databaseList = readFromDatabase(inputValue); // CPU: 1 Sec computing var cpuList = computeCPUData(databaseList); // UI showInUI(cpuList); }); thread.start(); } Synchronous: Thread per Request for(int i = 1 ; i <= 8; ++i) { final int arg = i; // Stage 1: DB Access CompletableFuture.supplyAsync(()->readFromDatabase(arg)) // Callback Stage 2: CPU Computation .thenApplyAsync((List<Integer> dbResultSet) -> { return computeCPUData(dbResultSet); }) // Callback Stage 3: UI Rendering .thenAcceptAsync((cpuData) ->{ showInUI(cpuData); }); } Asynchronous Programming: CompletableFutures Simple but inefficient Efficient, but own programming model Complex Programming
  • 13.
    © Marwan Abu-Khalil Goal §Simple sequential programming o Like classic threads § Efficient asynchronous execution o Like Reactive Streams Mechanism o OS thread: Release in case of blocking o Asynchrony: Managed automatically Technological background o Mapping Virtual -> Platform-Thread o Operating System asynchronous IO o Non-preemtive scheduling Virtual Threads combine the best of both worlds: Sequential programming + asynchronous execution Page 15
  • 14.
    © Marwan Abu-Khalil §1. Why is a platform thread expensive? o Stack: Memory o OS-Scheduling: CPU § 2. Why is a virtual thread cheap? o Dynamic stack o JVM scheduling o Executed by platform thread § 3. What happens when a virtual thread calls a blocking OS operation? o Carrier thread released o Carrier executes other virtual thread o After blocking call returns: Virtual thread runnable Recap Page 23
  • 15.
    © Marwan Abu-Khalil Whathappens when a new virtual thread is created? § Instance of virtual thread is created § New virtual thread mapped to platform thread from pool § Associated platform thread runs virtual thread § Platform thread called "carrier thread" API and usage of virtual threads Page 26
  • 16.
    © Marwan Abu-Khalil 1.Class Thread 2. ExecutorService (Pool) 3. ThreadBuilder Virtual-Thread extends Thread => Key for simple migration Ways to start a Virtual Thread Page 27 // Start: Class Thread Thread virtualThread = Thread.startVirtualThread(() ->{}); // Start: ExecutorService Executors.newVirtualThreadPerTaskExecutor().submit(() -> {}); // Start: ThreadBuilder Thread.ofVirtual().name("MyVirtualThread").unstarted(() -> {}).start();
  • 17.
    © Marwan Abu-Khalil §ExecutorService creation: newVirtualThreadPerTaskExecutor() § Virtual threads never reused § Virtual thread performs one single task, then dies! § Future: Obtain result asynchronously Option 2: Executor Service Page 29 // Pool Interface: ExecutorService ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); // Start Future<?> threadResult = executor.submit(() -> { System.out.println("Virtual Thread via Executor ” + Thread.currentThread()); }); // Wait threadResult.get();
  • 18.
    © Marwan Abu-Khalil §Virtual threads can be instantiated at ”unlimited” amount o Since they are extremely "cheap" § Reuse is pointless o Virtual threads should never be pooled, they are too cheap o Only platform threads should be pooled (e.g. by ExecutorService) § Beware of "deep stacks" o Performance advantage may be lost o Long running tasks are not good candidates for virtual threads Important Guidlines for using Virtual Threads Page 33
  • 19.
    © Marwan Abu-Khalil 1Understanding Virtual Threads 2 Performance & Scalability o Is a Virtual Thread faster? o How can more Concurrency increase Performance? o Examples for Scalability and Performance 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features 6 Behind the Scenes Agenda Page 34 Ask your questions in the chat
  • 20.
    © Marwan Abu-Khalil NO!Computing speed on CPU is identical!!! § How can virtual threads increase performance? § Virtual threads "only" increase number of simultaneously blocking calls => More simultaneous tasks => More clients at the same time => Higher scalability => Higher throughput => Overall performance improves Is a Virtual Thread faster than a Platform Thread??? Page 35
  • 21.
    © Marwan Abu-Khalil §Little’s law (John Little, 1954) o Theoretic background for performance increase o Increased concurrency with constant response time implies higher throughput § Modern OS o Can handle many (thousands) simultaneous threads o BUT: Application shoud use few, because they are expensive § Thread Pools provide efficency o Pool size according to number of CPU-cores o Threads kept busy Why is scalabilty a challenge with classic threads? …and how can we gain performance? Page 36 Little’s Law Concurrency => Throughput => Performance!
  • 22.
    © Marwan Abu-Khalil Moresimultaneous Clients through Thread Virtualization Page 37 Classic Thread Model Expensive platform threads block during I/O => Few concurrent clients Virtual Thread Model Platform threads always running => Many concurrent clients
  • 23.
    © Marwan Abu-Khalil §10,000 Platform-Threads start o After 4000 threads crash: OutOfMemoryError § Alternative: Start 10,000 virtual threads o Runs smoothly § Crucial: blocking OS call (e.g.sleep()) § Effect of Virtual Threads Architecture o Number of parallel tasks massively increased o Little's Law: Throughput increased Example Scalability Page 39 Platform Threads: Crash Virtual Threads: Scale Real limit depends on OS, HW and configuration
  • 24.
    © Marwan Abu-Khalil §Platform threads start § sleep(): Blocking call § After 4000 threads are started: OutOfMemoryError 10,000 Platform Threads: Crash Page 40 for(int i = 0; i < 1_000_0; ++i) { final int cnt = i; // Launch Platform Thread Thread thread = new Thread(()->{ System.out.println("New OS Thread"+ cnt); // Sleep (blocking call) Thread.sleep(1000); // Exception handling omitted }); thread.start(); } 2 1 Adapt thread count and sleep time to your platform for experiments 3
  • 25.
    © Marwan Abu-Khalil 10,000Virtual-Threads: Start easily Page 41 for(int i = 0; i < 10_000; ++i) { final int cnt = i; // Starting virtual thread Thread.startVirtualThread(()->{ System.out.println(”New virtual Thread: " + cnt); sleep(1000); }); } Where does this help? Scalable Server
  • 26.
    © Marwan Abu-Khalil PerformanceExample: Increase through virtual threads factor 10!! Page 43 // Variant 1 Platform Threads: 10 seconds, Pool of 1000 Threads //ExecutorService pool = Executors.newFixedThreadPool(1000); // Variant 2 Virtual Threads: 1 second ExecutorService pool = Executors.newVirtualThreadPerTaskExecutor(); long start = System.currentTimeMillis(); for(int i = 0 ; i <= 10_000; ++i) { final int loop_cnt = i; pool.submit(() -> { // Blocking call (exception handling omitted) Thread.sleep(1000); System.out.println("Job " + loop_cnt + " woke up " + (System.currentTimeMillis() - start) / 1000 + " Seconds "); } } One second with 10,000 virtual threads 10 seconds with 1,000 platform threads More simultaneous tasks => Better overall performance
  • 27.
    © Marwan Abu-Khalil Positive §Higher scalability compared to platform threads § Performance can be massively improved by high scalability (Little's Law) Conclusion on Performance and Scalability of Virtual Threads Page 51 Negative § Blocking calls necessary to profit form virtual threads § Not all architectures, use cases, and systems can benefit from virtual thread migration
  • 28.
    © Marwan Abu-Khalil 1Understanding Virtual Threads 2 Performance & Scalability 3 Architecture and Blocking Calls o Rules for Migration o Relevance of blocking Calls o Examples for Scheduling Behavior 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features 6 Behind the Scenes Agenda Page 52 Ask your questions in the chat
  • 29.
    © Marwan Abu-Khalil 1.Performance limited by amout of available threads o Application could run faster with more threads o Rationale: Virtual threads only add concurrency, not paralleleism, not computing power 2. Significant time spent in blocking OS-calls („IO-Bound“) o Rationale: Virtual threads change system behaviour only during blocking OS-calls Two necessary Pre-Conditions for Performance Gain through Migration to Virtual Threads Page 53 CPU-bound Apps DO NOT BENEFIT!!! except in rare corner cases where context switching is a bottleneck see Quarkus Docu: https://quarkus.io/guides/virtual-threads#cpu-bound
  • 30.
    © Marwan Abu-Khalil §Typical server application o Significant amount of time: Blocking calls o E.g. database, internal and external services § Thread per Request o Simple to program o Scales only to thread limit of OS § Idea of Virtual Threads o Release OS thread on blocking call o Inside the JVM process: Lock.lock(), Thread.sleep()... o Outside, I/O: Socket, File Access... Relevance and handling of blocking calls (recap) Page 54
  • 31.
    © Marwan Abu-Khalil §A lot of virtual threads wish to execute sleep() § Single Platform Thread: Executes all virtual threads one at a time § All virtual threads block in sleep(): transferred to unmouted state § sleep() call returns: virtual thread is runnable again Example: Many virtual threads call sleep() at the same time Page 57
  • 32.
    © Marwan Abu-Khalil §Many (1000) Virtual Threads o Start o Each calls sleep() § Few (8) Platform Threads o Execute 1000 Virtual Threads Output shows: Many virtual threads executed by a few platform threads Page 58 for(int i = 0; i < 1000; ++i) { final int cnt = i; Thread.startVirtualThread(() ->{ System.out.println("Virtual Thread Nr. " + cnt + " " + Thread.currentThread()); // Blocking call releases Carrier-Thread sleep(1000); }); } 1000 Virtual Threads 8 Platform Threads
  • 33.
    © Marwan Abu-Khalil SchedulerDynamics: Many Virtual Threads call sleep()
  • 34.
    © Marwan Abu-Khalil Scenario:Queue of limited size § Many Virtual Threads call take(): blocking § Few Virtual Threads call put(): blocking § Executed by limited size Platform Thread Pool Example: Producer-Consumer with Blocking Queue Page 66 Comparison: Fork-Join-Tasks § May deadlock in queuing scenario § Do not handle blocking efficiently Behavior § Carrier released on blocking take() and put() § All threads run smoothly, no blocking
  • 35.
    © Marwan Abu-Khalil §10 virtual threads on 8-core computer, array with 10 slots § Each thread counts up counter in array infinitely § Result: only the first 8 slots are accessed, as only 8 virtual threads run actually § Platform threads instead: All fields in array are incremented Example: Missing preemption changes program semantics Page 69 long[] numbers = new long[10]; // 10 Virtual Threads: // Only 8 array slots processed on 8-Core CPU ExecutorService pool = Executors.newVirtualThreadPerTaskExecutor(); for(int i = 0 ; i < 10; ++i) { final int j = i; pool.execute(() ->{ while(true) { numbers[j]+=1; } }); } sleep(1000); System.out.println(Arrays.toString(numbers)); Rare corner case….
  • 36.
    © Marwan Abu-Khalil Virtualthreads characteristics § Reuse is pointless o Virtual threads never pooled! o Only platform threads pooled (ExecutorService) § Beware of "deep stacks” o Performance advantage may vanish § No Preemption o Application semantics can change Rules for the use of Virtual Threads and for Migration Recap / Summary Page 71 Migration requires two Pre-Conditions 1. Performance limited by amount of available threads 2. Significant time spent in blocking OS-calls
  • 37.
    © Marwan Abu-Khalil 1Understanding Virtual Threads 2 Performance & Scalability 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach o Reactive Streams comparison o JDK Alternatives: Fork-Join, Parallel Streams 5 Emerging Language Features 6 Behind the Scenes Agenda Page 91 Ask your questions in the chat
  • 38.
    © Marwan Abu-Khalil Discussionsbetween Reactive Streams and Virtual Threads Advocates § Arguments of virtual thread community (e.g. Brian Goetz) o Reactive streams don't fit well into Java Platform o Unit of application's concurrency is pipeline stage o Unit of the platform's concurrency is thread o Tools, stack traces, profilers, debuggers not well usable o "Foreign" programming model: without support in Java language / platform See https://www.infoq.com/articles/java-virtual-threads/ „What About Reactive“ § Arguments of ReacitveStreams community (e.g. Thomasz Nurkiewitz) o Only benefit of virtual threads programming model: easy asynchrony o Other Reactive Streams features missing: Backpressure, Change Propagation, Composability See: https://www.infoq.com/presentations/loom-java-concurrency/ Reactive Streams Comparison Page 93 Flux.range(1, 8) // DB Access: 1 Sec blocking .map( and -> readFromDatabase(i)) // Stage decoupling .publishOn(Schedulers.parallel()) .map( list -> computeCPUData(list)) .publishOn(Schedulers.parallel()) .subscribe( list->showInUI(cpuList)); Reactive Streams Example
  • 39.
    © Marwan Abu-Khalil VirtualThreads § Make IO-bound applications scalable See: Brian Getz, Virtual Threads: new Foundations for Java High Scale Applications https://www.infoq.com/articles/java-virtual-threads/ ForkJoin and ParallelStreams § Ideal for CPU-bound applications o Many asynchronous tasks run on top of few threads § Not suitable for IO bound applications o Blocking OS call not handled well o Block underlying pool thread o Risk: Deadlock, or alternatively high memory consumption if pool grows Comparison Virtual-Threads vs. Fork-Join-Tasks & Parallel-Streams Page 94 IO-bound optimized CPU-bound optimized Fork Join Tasks Tech-Stack !"#A%C"'( F*+A%F#,, FJ#,*.%/""0 1/O 1/O P4%45J,.S0,# /*#*00,0T4U#,*9+ !"#$B&'(F*+', -./&(.$0*'"-1O#.-"+-, 1"( Virtual-Thread blocking call handling:
  • 40.
    © Marwan Abu-Khalil §2 Virtual Threads run and call put() § Queue full, put() blocks V-T 2 § Carrier thread P-T 2 is freed § P-T 2 now executes V-T 3 § take() frees space in the queue § V-T 2 unblocking § but has no carrier yet Blocking Queue with Virtual Threads Scenario Page 95
  • 41.
    © Marwan Abu-Khalil §Fork-Join-Tasks o Blocking-Queue: Deadlock § put() blocks when queue full § ForkJoinTasks block Pool-Threads § No more pool threads § No ForkJoinTask runs for take() What fork-join tasks can't do that virtual threads can: e.g. producer-consumer with blocking queue Page 96
  • 42.
    © Marwan Abu-Khalil Technologyselection according to functional and non fuctional properties Page 103 Usecase Virtual Thread Platform Thread Fork-Join-Task Parallel- Stream Reactive- Stream Blocking-IO Yes perfect use-case Yes No Blocks Pool Thread No Blocks Pool Thread Yes Asynchrony System Architecture Structure Yes But focus on server scalabilty Yes Perfect use case No No blocking IO handling No More design level, no blocking IO Yes Many subscribers back-pressure Recursive Algorithm Yes Cheap parallelsim Risk: No preemption Probably not Caution: Memory requirements Yes Perfect Use-Case No Recursion not feasible within pipeline Probably not Focus: distributed concurrent system Pipeline Data Processing Probably not No API support Probably not No API support No No blocking Yes Perfect use-case Yes not primarily for parallelizing pipeline Lots of data infinite streams No Short running Yes Long running No short running No Cannot be partitioned efficiently Yes Perfect use-case API
  • 43.
    © Marwan Abu-Khalil 1Understanding Virtual Threads 2 Performance & Scalability 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features o Structured Concurrency o Scoped Values 6 Behind the Scenes Agenda Page 104 Ask your questions in the chat
  • 44.
    © Marwan Abu-Khalil §Goals o Handle group of virtual threads as single unit o Eliminate concurrent programming risks regarding cancellation and shutdown § Central idea o Combine parallel tasks into a "scope" that succeed or fail together o One thread throws exception: Full “scope” exited § Constructs o StructuredTaskScope: Combines multiple virtual threads into one unit o Subtask<String> subTask1 = scope.fork(() -> {...}): fork starts new Virtual Thread o scope.join(): Waits for all threads in the scope o scope.throwIfFailed(); Terminates scope by an exception when a thread throws errors o StructuredTaskScoped.Joiner: Configures join()-behavioir, e.g. anySuccessfulResultOrThrow() / awaitAll() / awaitAllSuccessfulOrThrow(), https://openjdk.org/jeps/505 (for Java 25) https://openjdk.org/jeps/480 (for Java 23) Structured Concrurency JEP 480, 505, Preview Page 105 Java 25 / Java 23 differences, e.g: public static <T> StructuredTaskScope<T, Void> open()
  • 45.
    © Marwan Abu-Khalil StructuredConcurrency Example (Java 23 Version) Page 106 try(var scope = new StructuredTaskScope.ShutdownOnFailure()){ // Start Subtask Subtask<String> subTask1 = scope.fork(() -> { System.out.println("Task 1 called in " + Thread.currentThread()); return "Hello"; }); // Start Subtask Subtask<String> subTask2 = scope.fork(() -> { for(int i = 0; i < 1000; ++i) { System.out.println("Task 2 loop: " + i +" called in " + Thread.currentThread()); } return ”World"; }); scope.join(); scope.throwIfFailed(); System.out.println(subTask1.get()); System.out.println(subTask2.get()); } Two threads handled as one singe unit wait for all! propagate failures common “scope” bundles virtual threads together
  • 46.
    © Marwan Abu-Khalil §Idea o ThreadLocal variables optimized for use with virtual threads o Immutable o Cheap o Shared by a hierarchy of virtual threads in a scope (StructuredTaskScope) § Elements o Declaration static final ScopedValue<... > V = ScopedValue.newInstance(); o Setting the value ScopedValue.where(V, <value>) o Binding to lambda expression ScopedValue.run(() -> { ... V.get() ... call methods ... }); o Accessing the value V.get() https://openjdk.org/jeps/487 Scoped Values JEP 487, Preview Page 108
  • 47.
    © Marwan Abu-Khalil ScopedValues Example Page 109 Declaring Scoped Value static ScopedValue<String> SCOPED_VALUE_EXAMPLE = ScopedValue.newInstance(); Thread virtThread1 = Thread.startVirtualThread(() -> { Bind scoped value with where() and define scope with run() ScopedValue.where(SCOPED_VALUE_EXAMPLE, "Hallo").run(() -> { String valueinThread = SCOPED_VALUE_EXAMPLE.get(); System.out.println("Thread 1: " + valueinThread); }); }); Thread virtThread2 = Thread.startVirtualThread(() -> { Different value in another scope ScopedValue.where(SCOPED_VALUE_EXAMPLE, "GutenTag").run(() -> { String valueinThread = SCOPED_VALUE_EXAMPLE.get(); System.out.println("Thread 2: " + valueinThread); }); }); single instance Assign value for thread 1 other value for thread 2 different outputs Core feature: Anywhere in the code available without argument
  • 48.
    © Marwan Abu-Khalil 1Understanding Virtual Threads 2 Performance & Scalability 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features 6 Behind the Scenes o JVM Virtual Threads Architecture o Consequences for Application Design Agenda Page 110 Ask your questions in the chat
  • 49.
    © Marwan Abu-Khalil 1.Blocking call: Carrier Thread released § M:N Mapping: Virtual thread run by several platform threads § New carrier after blocking call 2. Dynamic Stack § Stack can grow and shrink (StackChunk objects, lazy-loading) § Mounting / unmounting: Stack-frames copied from carrier's stack to heap (& vice versa) 3. Continuations § Virtual threads are realized as “continuations” § “one shot delimited continuations” theoretic concept behind 4. User Mode Scheduling § No preemption: A virtual thread runs to completion Architecture of virtual threads = > Consequences for App Design and Behavior Page 111 Changed program semantics, e.g. starvation Cheap scheduling Beware of deep stacks Memory saving Only IO-bound apps benefit Performance optimization Easy migration Automatic asynchrony
  • 50.
    © Marwan Abu-Khalil Conclusionon Virtual Threads Page 114 Positive § Extremely highly scalable o Many thousands of simultaneous tasks § Massive performance boost possible o Throughput o Little’s Law § Saved resources o Memory and CPU o Platform Threads § Simple programming model o Like classic threads o Easy migration o Sequential programming, asych. execution Carefully consider before migration § Only effective with significant blocking time o Blocking time per client call relevant o Only for IO bound applications o No benefit for computationally intensive applications § High degree of concurrency required o Unreachable with platform threads o Thousands, possibly millions § Semantic change possible (rare case!) o No preemption
  • 51.
    © Marwan Abu-Khalil 1Understanding Virtual Threads 2 Performance & Scalability 3 Architecture and Blocking Calls 4 Selecting the Suitable Concurrency Approach 5 Emerging Language Features 6 Behind the Scenes Agenda in Retrospect Page 115
  • 52.
    © Marwan Abu-Khalil -Oracle Java Core Libraries Documentation: https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html - JEP Virtual Threads https://openjdk.org/jeps/425 and https://openjdk.org/jeps/444 - JEP Structured Concurrency: https://openjdk.org/jeps/453, https://openjdk.org/jeps/505 - Brian Goetz, 2022: New Foundations for Java High Scale Applications https://www.infoq.com/articles/java- virtual-threads/ - Michael Inden, 2025: Java 21 LTS bis 24 -- Coole neue Java-Features: Modernes Java leicht gemacht https://amzn.eu/d/2FrSinA - Sven Woltmann, 2022, nice little examples: https://www.happycoders.eu/de/java/virtual-threads/ - Nicolai Parlog, Oracle, 2022: https://blogs.oracle.com/javamagazine/post/java-loom-virtual-threads-platform-threads - Lutz Hühnken, entwickler.de 2020 https://entwickler.de/java/blick-in-die-fernere-zukunft - Reinald Menge-Sonntag, heise online 2022: https://www.heise.de/news/Java-19-verbessert-die-Nebenlaeufigkeit-mit-virtuellen- Threads-aus-Project-Loom-7269453.html - Ron Presler, QCon 2019: https://www.infoq.com/presentations/continuations-java/ - Thomasz Nurkiewitz, QCon 2022: https://www.infoq.com/presentations/loom-java-concurrency/ - Ricardo Cardin, 2023, good Examples about Threadpool and Scheduling: https://blog.rockthejvm.com/ultimate- guide-to-java-virtual-threads/#3-how-to-create-a-virtual-thread - Marwan Abu-Khalil, 2025 , Virtual Threads in Java: Performance und Skalierbarkeit in neuer Dimension, https://www.sigs.de/artikel/virtual-threads-in-java-performance-und-skalierbarkeit-in-neuer-dimension/ Literature and web links (some are in German, but still great!) Page 116
  • 53.
    © Marwan Abu-Khalil Contact seminar@abu-khalil.de MarwanAbu-Khalil Senior Software Architect Siemens AG Berlin, Germany www.linkedin.com/in/marwan-abu-khalil Marwan Abu-Khalil Page 117 Seminars § Technische Akademie Esslingen Software Architecture Introduction § iX Workshops, Heise Akademie Software-Architecture Introduction Conference Talks § W-JAX, Munich November 2025: Virtual Threads Workshop § JAX, Mainz Mai 2025: Reactive Streams Workshop Publication on Virtual Threads § Java Spektrum, 2.2025 Virtual Threads in Java: Performance und Skalierbarkeit in neuer Dimension
  • 54.
    © Marwan Abu-Khalil Page118 Q&A Ask your QUESTIONS in the chat!