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

Java 21: Virtual Threads

Java 21: Virtual Threads

Java 21 introduces lightweight concurrency with Virtual Threads.

Virtual threads are a different approach to asynchronous programming. Instead of having to rewrite everything using async/await keywords. Java will take care of everything.

Discover the changes introduced with JDK 21 and learn how Virtual Threads behaves with code examples demonstrating I/O Bound Tasks, CPU Bound Tasks, and Cooperative CPU Bound Tasks. Learn how the synchronized keyword and locks work in the context of Virtual Threads.

https://youtu.be/JWZxyrHBppA

Matteo Bertozzi

September 19, 2023
Tweet

More Decks by Matteo Bertozzi

Other Decks in Programming

Transcript

  1. JDK 21
    LTS
    Virtual
    Threads
    a Different Approach to
    Async/Await

    View Slide

  2. Aims to Bring
    easy-to-use, high-throughput,
    lightweight concurrency
    and new programming models
    on the Java platform.
    JDK 21
    LTS

    View Slide

  3. JDK 21: Virtual Threads
    A different Approach to asynchronous programming
    C#, Python, Javascript, C++, Rust
    async/await
    Introduced New Keywords
    requiring a significant rewrite
    to take advantage of this model
    choose
    code compatibility
    minimizing the impact on existing code
    to benefit from this model

    View Slide

  4. JDK 21: Threads
    Platform Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    // create a platform thread, and use .start() to start it.
    Thread thread = new Thread(Runnable, "thread-name")
    thread.start();
    // create a platform thread, and use .start() to start it.
    Thread thread = Thread.ofPlatform().name("thread-name").unstarted(Runnable);
    thread.start();
    // create a platform thread and start it. No need to call .start()
    Thread thread = Thread.ofPlatform().name("thread-name").start(Runnable);

    View Slide

  5. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Platform Threads & Executor Services

    View Slide

  6. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }
    Platform Threads & Executor Services

    View Slide

  7. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  8. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  9. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  10. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  11. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  12. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  13. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  14. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  15. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  16. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  17. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  18. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  19. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  20. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  21. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  22. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  23. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  24. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  25. JDK 21: Threads
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue
    Platform Threads & Executor Services
    try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    for (int i = 0; i < 100; ++i) {
    executor.submit(() -> myTask());
    }
    }

    View Slide

  26. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue

    View Slide

  27. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue

    View Slide

  28. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue

    View Slide

  29. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue

    View Slide

  30. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Kernel space
    User space (JVM)
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    Task Queue

    View Slide

  31. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    In most backend services
    Slow Tasks
    are I/O Bound Tasks

    View Slide

  32. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    System.out.println("Active Threads " + Thread.activeCount());
    for (int i = 0; i < 128; ++i) {
    httpClient.sendAsync(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    System.out.println("Active Threads " + Thread.activeCount());
    }
    CompletableFuture and the Async feeling

    View Slide

  33. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    System.out.println("Active Threads " + Thread.activeCount());
    for (int i = 0; i < 128; ++i) {
    httpClient.sendAsync(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    System.out.println("Active Threads " + Thread.activeCount());
    }
    CompletableFuture and the Async feeling
    My Task
    Not being blocked

    View Slide

  34. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    System.out.println("Active Threads " + Thread.activeCount());
    for (int i = 0; i < 128; ++i) {
    httpClient.sendAsync(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    System.out.println("Active Threads " + Thread.activeCount());
    }
    CompletableFuture and the Async feeling
    All the threads created by .sendAsync()
    Waiting for I/O
    My Task
    Not being blocked

    View Slide

  35. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    System.out.println("Active Threads " + Thread.activeCount());
    for (int i = 0; i < 128; ++i) {
    httpClient.sendAsync(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    System.out.println("Active Threads " + Thread.activeCount());
    }
    CompletableFuture and the Async feeling
    All the threads created by .sendAsync()
    Waiting for I/O
    My Task
    Not being blocked

    View Slide

  36. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    System.out.println("Active Threads " + Thread.activeCount());
    for (int i = 0; i < 128; ++i) {
    httpClient.sendAsync(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    System.out.println("Active Threads " + Thread.activeCount());
    }
    CompletableFuture and the Async feeling
    All the threads created by .sendAsync()
    Waiting for I/O
    My Task
    Not being blocked

    View Slide

  37. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    System.out.println("Active Threads " + Thread.activeCount());
    for (int i = 0; i < 128; ++i) {
    httpClient.sendAsync(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    System.out.println("Active Threads " + Thread.activeCount());
    }
    CompletableFuture and the Async feeling
    All the threads created by .sendAsync()
    Waiting for I/O
    My Task
    Not being blocked

    View Slide

  38. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    System.out.println("Active Threads " + Thread.activeCount());
    for (int i = 0; i < 128; ++i) {
    httpClient.sendAsync(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    System.out.println("Active Threads " + Thread.activeCount());
    }
    CompletableFuture and the Async feeling
    All the threads created by .sendAsync()
    Waiting for I/O
    My Task
    Not being blocked

    View Slide

  39. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    System.out.println("Active Threads " + Thread.activeCount());
    for (int i = 0; i < 128; ++i) {
    httpClient.sendAsync(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    System.out.println("Active Threads " + Thread.activeCount());
    }
    CompletableFuture and the Async feeling
    All the threads created by .sendAsync()
    Waiting for I/O
    My Task
    Not being blocked

    View Slide

  40. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    System.out.println("Active Threads " + Thread.activeCount());
    for (int i = 0; i < 128; ++i) {
    httpClient.sendAsync(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    System.out.println("Active Threads " + Thread.activeCount());
    }
    CompletableFuture and the Async feeling
    All the threads created by .sendAsync()
    Waiting for I/O
    My Task
    Not being blocked

    View Slide

  41. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    System.out.println("Active Threads " + Thread.activeCount());
    for (int i = 0; i < 128; ++i) {
    httpClient.sendAsync(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    System.out.println("Active Threads " + Thread.activeCount());
    }
    CompletableFuture and the Async feeling
    All the threads created by .sendAsync()
    Waiting for I/O
    My Task
    Not being blocked

    View Slide

  42. JDK 21: Executor Services
    Slow Tasks & Completable Future
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Platform Threads are not cheap
    - startup time: ~1ms
    - memory consumption: 2MB of stack
    - context switch: ~100μs
    System.out.println("Active Threads " + Thread.activeCount());
    for (int i = 0; i < 128; ++i) {
    httpClient.sendAsync(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    System.out.println("Active Threads " + Thread.activeCount());
    }
    CompletableFuture and the Async feeling
    All the threads created by .sendAsync()
    Waiting for I/O
    My Task
    Not being blocked

    View Slide

  43. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    JDK 21: Threads
    Virtual Threads
    User space (JVM)
    // create a virtual thread and start it.
    Thread thread = Thread.startVirtualThread(Runnable);
    // create a virtual thread and start it.
    Thread thread = Thread.ofVirtual().name(“thread-name").start(Runnable);
    // create a virtual thread, and use .start() to start it.
    Thread thread = Thread.ofVirtual().name("thread-name").unstarted(Runnable);
    thread.start();
    Virtual
    Threads
    JVM

    View Slide

  44. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    JDK 21: Threads
    Virtual Threads
    Eliminates the overhead
    of
    I/O Bound Tasks

    View Slide

  45. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    JDK 21: Threads
    Virtual Threads
    User space (JVM)
    Virtual
    Threads
    JVM

    View Slide

  46. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    JDK 21: Threads
    Virtual Threads
    User space (JVM)
    Virtual
    Threads
    JVM
    Use them for I/O Bound Tasks

    View Slide

  47. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    JDK 21: Threads
    Virtual Threads
    User space (JVM)
    Virtual
    Threads
    JVM
    Use them for I/O Bound Tasks
    Spends most of the time
    using CPU
    Spends most of the time
    waiting for I/O
    Longer CPU bursts Shorter CPU bursts
    CPU Bound I/O Bound

    View Slide

  48. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    JDK 21: Threads
    Virtual Threads
    User space (JVM)
    Virtual
    Threads
    JVM
    Almost no changes to the code required!
    Java did all of the work underneath
    Rewriting the I/O & Blocking Operations
    To Cooperate with the Virtual Threads Scheduler

    View Slide

  49. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    JDK 21: Threads
    Virtual Threads
    User space (JVM)
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    executor.submit(() -> myTask());
    }
    Virtual
    Threads
    JVM

    View Slide

  50. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    JDK 21: Threads
    Virtual Threads
    User space (JVM)
    // create a virtual thread and start it.
    Thread thread = Thread.startVirtualThread(Runnable);
    // create a virtual thread and start it.
    Thread thread = Thread.ofVirtual().name(“thread-name").start(Runnable);
    // create a virtual thread, and use .start() to start it.
    Thread thread = Thread.ofVirtual().name("thread-name").unstarted(Runnable);
    thread.start();
    Virtual
    Threads
    JVM

    View Slide

  51. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    JDK 21: Threads
    Virtual Threads
    // create a platform thread and start it. No need to call .start()
    Thread thread = Thread.ofPlatform().name(“my-thread-name”).start(Runnable);
    // create a virtual thread and start it.
    Thread thread = Thread.ofVirtual().name(“my-thread-name”).start(Runnable);
    boolean isVirtual = thread.isVirtual();

    View Slide

  52. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    JDK 21: Threads
    Virtual Threads
    // create a platform thread and start it. No need to call .start()
    Thread thread = Thread.ofPlatform().name(“my-thread-name”).start(Runnable);
    // create a virtual thread and start it.
    Thread thread = Thread.ofVirtual().name(“my-thread-name”).start(Runnable);
    boolean isVirtual = thread.isVirtual();
    Thread[#29,my-thread-name,5,main]
    VirtualThread[#30,my-thread-name]/runnable@ForkJoinPool-1-worker-1
    jstack or Thread.currentThread() shows

    View Slide

  53. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    JDK 21: Threads
    Virtual Threads
    // create a platform thread and start it. No need to call .start()
    Thread thread = Thread.ofPlatform().name(“my-thread-name”).start(Runnable);
    // create a virtual thread and start it.
    Thread thread = Thread.ofVirtual().name(“my-thread-name”).start(Runnable);
    boolean isVirtual = thread.isVirtual();
    Thread[#29,my-thread-name,5,main]
    VirtualThread[#30,my-thread-name]/runnable@ForkJoinPool-1-worker-1
    jstack or Thread.currentThread() shows

    View Slide

  54. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Kernel space
    User space (JVM)
    Virtual
    Threads
    Carrier
    Threads

    View Slide

  55. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Kernel space
    User space (JVM)
    Virtual
    Threads
    Carrier
    Threads
    ForkJoinPool with FIFO order

    View Slide

  56. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Kernel space
    User space (JVM)
    Virtual
    Threads
    Carrier
    Threads
    ForkJoinPool with FIFO order
    -Djdk.virtualThreadScheduler.parallelism=16
    -Djdk.virtualThreadScheduler.maxPoolSize=256
    The number of platform threads available for scheduling virtual threads.
    It defaults to the number of available processors.
    The maximum number of platform threads available to the scheduler.
    It defaults to 256.

    View Slide

  57. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread

    View Slide

  58. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...

    View Slide

  59. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...

    View Slide

  60. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...

    View Slide

  61. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...

    View Slide

  62. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...

    View Slide

  63. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks

    View Slide

  64. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap

    View Slide

  65. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  66. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  67. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  68. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  69. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  70. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  71. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  72. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  73. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  74. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  75. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  76. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  77. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  78. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  79. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  80. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  81. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  82. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap
    Task
    State

    View Slide

  83. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap

    View Slide

  84. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    Virtual
    Threads
    Carrier
    Thread
    // some cpu bound code
    long result = 0;
    for (int i = 0; i < 100; ++i) {
    result += i * 3;
    }
    // some blocking (I/O bound) code
    HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create(“https://myservice/test”))
    .GET()
    .build(), BodyHandlers.discarding());
    // more cpu bound code
    if (resp.statusCode() != 200) {
    ...
    Waiting
    Tasks
    JVM Heap

    View Slide

  85. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    public void myTask() {
    // each execution step may run on a different Carrier Thraed
    cpuBoundOperations(); // run on CarrierThread-5
    ioBoundOperations(); // goes to "waiting"
    cpuBoundOperations(); // run on CarrierThread-3
    ioBoundOperations(); // goes to "waiting"
    cpuBoundOperations(); // run on CarrierThread-3
    // ...
    }

    View Slide

  86. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    public void myTask() {
    // each execution step may run on a different Carrier Thraed
    cpuBoundOperations(); // run on CarrierThread-5
    ioBoundOperations(); // goes to "waiting"
    cpuBoundOperations(); // run on CarrierThread-3
    ioBoundOperations(); // goes to "waiting"
    cpuBoundOperations(); // run on CarrierThread-3
    // ...
    }
    ThreadLocals are available for compatibility
    but not really useful. Do not pool VirtualThreads!

    View Slide

  87. Virtual Threads
    User-mode threads
    scheduled by the Java Runtime
    rather than the operating system
    Platform Threads
    Typically mapped 1:1 to kernel threads
    scheduled by the operating system.
    Carrier Threads
    Set of Platform threads responsible for
    running virtual threads.
    JDK 21: Threads
    Platform, Virtual & Carrier Threads
    public void myTask() {
    // each execution step may run on a different Carrier Thraed
    cpuBoundOperations(); // run on CarrierThread-5
    ioBoundOperations(); // goes to "waiting"
    cpuBoundOperations(); // run on CarrierThread-3
    ioBoundOperations(); // goes to "waiting"
    cpuBoundOperations(); // run on CarrierThread-3
    // ...
    }
    ThreadLocals are available for compatibility
    but not really useful. Do not pool VirtualThreads!
    ScopedValue SHARED_OBJECT = ScopedValue.newInstance();
    ScopedValues, the better alternative to ThreadLocal
    are only available as preview (in JDK 21)

    View Slide

  88. Code Examples
    Let's see how Virtual Threads behaves

    View Slide

  89. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }

    View Slide

  90. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    We are using the synchronous .send()
    No callbacks, futures & co

    View Slide

  91. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }

    View Slide

  92. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  93. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  94. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  95. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  96. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  97. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  98. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  99. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  100. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  101. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  102. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  103. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  104. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  105. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  106. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  107. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  108. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  109. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  110. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  111. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  112. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  113. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  114. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  115. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  116. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  117. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  118. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  119. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  120. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  121. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  122. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  123. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  124. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  125. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  126. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  127. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  128. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  129. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  130. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  131. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  132. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  133. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  134. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  135. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  136. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  137. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static long ioBoundTask() {
    try {
    // calls a service that waits 5sec before responding…
    final HttpResponse resp = httpClient.send(HttpRequest.newBuilder()
    .uri(URI.create("https://hub.dummyapis.com/delay?seconds=5"))
    .GET()
    .build(), BodyHandlers.discarding());
    // ...
    return resp.statusCode();
    } catch (final Exception e) {
    // ignore...
    System.err.println("http req failed: " + e.getMessage());
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks

    View Slide

  138. JDK 21: Virtual Threads
    I/O Bound Tasks
    private static int sleepBoundTask() {
    try {
    // sleep() acts as an I/O operation, allowing the task unmount
    Thread.sleep(5_000);
    return 0;
    } catch (final InterruptedException e) {
    // ignore...
    return -1;
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    final Thread[] threads = new Thread[10];
    for (int i = 0; i < threads.length; ++i) {
    final int taskId = i;
    threads[i] = Thread.ofVirtual().start(() -> {
    sleepBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    for (final Thread thread : threads) {
    thread.join();
    final boolean isVirtual = thread.isVirtual();
    }

    View Slide

  139. JDK 21: Virtual Threads
    CPU Bound Tasks
    Virtual Threads are made for I/O Bound Tasks
    Let’s see how they will behave with CPU Bound Tasks

    View Slide

  140. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    There are no blocking points in the code
    To Unmount the Virtual Thread

    View Slide

  141. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads

    View Slide

  142. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads

    View Slide

  143. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads
    1. Completed in 5s

    View Slide

  144. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads
    1. Completed in 5s

    View Slide

  145. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads
    1. Completed in 5s
    2. Completed in 5s

    View Slide

  146. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads
    1. Completed in 5s
    2. Completed in 5s

    View Slide

  147. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads
    1. Completed in 5s
    2. Completed in 5s
    3. Completed in 10s
    4. Completed in 10s

    View Slide

  148. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads
    1. Completed in 5s
    2. Completed in 5s
    3. Completed in 10s
    4. Completed in 10s

    View Slide

  149. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads
    1. Completed in 5s
    2. Completed in 5s
    3. Completed in 10s
    4. Completed in 10s
    5. Completed in 15s
    6. Completed in 15s

    View Slide

  150. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads
    1. Completed in 5s
    2. Completed in 5s
    3. Completed in 10s
    4. Completed in 10s
    5. Completed in 15s
    6. Completed in 15s

    View Slide

  151. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads
    1. Completed in 5s
    2. Completed in 5s
    3. Completed in 10s
    4. Completed in 10s
    5. Completed in 15s
    6. Completed in 15s
    7. Completed in 20s
    8. Completed in 20s

    View Slide

  152. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads
    1. Completed in 5s
    2. Completed in 5s
    3. Completed in 10s
    4. Completed in 10s
    5. Completed in 15s
    6. Completed in 15s
    7. Completed in 20s
    8. Completed in 20s

    View Slide

  153. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Threads
    1. Completed in 5s
    2. Completed in 5s
    3. Completed in 10s
    4. Completed in 10s
    5. Completed in 15s
    6. Completed in 15s
    7. Completed in 20s
    8. Completed in 20s
    9. Completed in 25s
    10.Completed in 25s

    View Slide

  154. JDK 21: Virtual Threads
    CPU Bound Tasks
    private static long cpuBoundTask() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    count++;
    }
    return count;
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=2
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    For CPU bound Tasks
    Virtual Threads gives no advantage
    over traditional
    (Platform Thread based)
    ExecutorServices
    And I/O Bound Tasks
    Have to wait
    CPU Bound Tasks to Finish

    View Slide

  155. Virtual
    Threads
    Carrier
    Threads
    CPU Bound
    Tasks
    Platform
    Threads
    Send CPU and I/O bound tasks to dedicated executors
    ThreadPoolExecutor VirtualThraedPerTaskExecutor
    JDK 21: Virtual Threads

    View Slide

  156. JDK 21: Virtual Threads
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }
    CPU Bound Tasks
    can cooperate
    Using the yield() method

    View Slide

  157. JDK 21: Virtual Threads
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    Carrier
    Thread
    Waiting
    Tasks
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  158. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  159. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  160. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  161. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  162. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  163. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  164. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  165. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  166. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  167. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  168. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  169. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  170. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  171. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  172. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  173. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  174. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  175. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  176. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  177. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  178. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  179. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  180. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  181. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  182. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  183. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  184. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  185. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  186. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  187. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  188. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  189. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  190. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  191. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  192. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  193. JDK 21: Virtual Threads
    Carrier
    Thread
    Waiting
    Tasks
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }

    View Slide

  194. JDK 21: Virtual Threads
    Cooperative CPU Bound Tasks
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    cpuBoundTaskWithYield();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    private static long cpuBoundTaskWithYield() {
    final long startTime = System.nanoTime();
    long count = 0;
    while ((System.nanoTime() - startTime) < TimeUnit.SECONDS.toNanos(5)) {
    if (count++ % 100 == 0) {
    Thread.yield();
    }
    }
    return count;
    }
    Slower than running the task alone
    (Since the CPU is shared)
    But it’s the same behaviour
    of running multiple platform Threads

    View Slide

  195. JDK 21: Virtual Threads
    The synchronized keyword
    private final static Object[] lock = new Object[4];
    static {
    for (int i = 0; i < lock.length; ++i) {
    lock[i] = new Object();
    }
    }
    private static long ioSynchronizedTask(final int taskId) {
    synchronized (lock[taskId % lock.length]) {
    return ioBoundTask();
    }
    }
    synchronized
    will block
    the carrier thread

    View Slide

  196. JDK 21: Virtual Threads
    The synchronized keyword
    private final static Object[] lock = new Object[4];
    static {
    for (int i = 0; i < lock.length; ++i) {
    lock[i] = new Object();
    }
    }
    private static long ioSynchronizedTask(final int taskId) {
    synchronized (lock[taskId % lock.length]) {
    return ioBoundTask();
    }
    }
    Multiple synchronized Object
    Will not help
    If you are lucky
    You’ll get the
    CPU Bound Task Behaviour
    Even on I/O Operations

    View Slide

  197. JDK 21: Virtual Threads
    The synchronized keyword
    private final static Object[] lock = new Object[4];
    static {
    for (int i = 0; i < lock.length; ++i) {
    lock[i] = new Object();
    }
    }
    private static long ioSynchronizedTask(final int taskId) {
    synchronized (lock[taskId % lock.length]) {
    return ioBoundTask();
    }
    }
    Remove the use of
    Synchronized

    View Slide

  198. JDK 21: Virtual Threads
    Locks: Reentrant Lock, Semaphores, …
    private static final ReentrantLock[] rlock = new ReentrantLock[4];
    static {
    for (int i = 0; i < rlock.length; ++i) {
    rlock[i] = new ReentrantLock();
    }
    }
    private static long ioLockedTask(final int taskId) {
    final ReentrantLock lock = rlock[taskId % rlock.length];
    lock.lock();
    try {
    return ioBoundTask(); // http.send(), sleep(), ...
    } finally {
    lock.unlock();
    }
    }
    // Run with -Djdk.virtualThreadScheduler.parallelism=1
    final long startTime = System.nanoTime();
    try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10; ++i) {
    final int taskId = i;
    executor.submit(() -> {
    ioLockedTask();
    long elapsedNs = System.nanoTime() - startTime;
    });
    }
    }
    4 Tasks will run concurrently
    Locks are a blocking operation
    Releasing the Virtual Thread from the Carrier

    View Slide

  199. JDK 21
    Virtual Threads
    Do not go and replace all your ExecutorServices with Virtual Threads!
    CPU Bound Tasks will not benefit from it
    Virtual Threads are made for I/O bound Tasks
    Spends most of the time
    using CPU
    Spends most of the time
    waiting for I/O
    Longer CPU bursts Shorter CPU bursts
    CPU Bound I/O Bound

    View Slide

  200. JDK 21
    Virtual Threads
    Do not go and replace all your ExecutorServices with Virtual Threads!
    CPU Bound Tasks will not benefit from it
    Virtual Threads are made for I/O bound Tasks
    Spends most of the time
    using CPU
    Spends most of the time
    waiting for I/O
    Longer CPU bursts Shorter CPU bursts
    CPU Bound I/O Bound
    Virtual
    Threads
    A Service or a Database

    View Slide

  201. JDK 21
    Virtual Threads
    Do not go and replace all your ExecutorServices with Virtual Threads!
    CPU Bound Tasks will not benefit from it
    Virtual Threads are made for I/O bound Tasks
    Spends most of the time
    using CPU
    Spends most of the time
    waiting for I/O
    Longer CPU bursts Shorter CPU bursts
    CPU Bound I/O Bound
    Virtual
    Threads
    A Service or a Database
    Can your Database, Service, Disk, …
    handle the extra concurrency?
    (Probably not)
    If you are using Virtual Threads
    You should limit the access
    To a Resource
    Using a Semaphore (or similar)

    View Slide