Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

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: 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
  2. 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);
  3. 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
  4. 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
  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 Task Queue Platform Threads & Executor Services try (ExecutorService executor = Executors.newFixedThreadPool(4)) { for (int i = 0; i < 100; ++i) { executor.submit(() -> myTask()); } }
  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 Task Queue Platform Threads & Executor Services try (ExecutorService executor = Executors.newFixedThreadPool(4)) { for (int i = 0; i < 100; ++i) { executor.submit(() -> myTask()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  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()); } }
  24. 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
  25. 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
  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
  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
  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
  29. 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
  30. 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
  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 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
  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 All the threads created by .sendAsync() Waiting for I/O My Task Not being blocked
  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 All the threads created by .sendAsync() Waiting for I/O My Task Not being blocked
  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
  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
  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
  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
  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
  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
  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
  41. 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
  42. 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
  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) Virtual Threads JVM
  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 User space (JVM) Virtual Threads JVM Use them for I/O Bound Tasks
  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 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
  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 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
  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) try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) { executor.submit(() -> myTask()); } Virtual Threads JVM
  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) // 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
  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 // 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();
  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 // 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
  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(); Thread[#29,my-thread-name,5,main] VirtualThread[#30,my-thread-name]/runnable@ForkJoinPool-1-worker-1 jstack or Thread.currentThread() shows
  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. 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
  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. 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
  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 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.
  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 Virtual Threads Carrier Thread
  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 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<Void> resp = httpClient.send(HttpRequest.newBuilder() .uri(URI.create(“https://myservice/test”)) .GET() .build(), BodyHandlers.discarding()); // more cpu bound code if (resp.statusCode() != 200) { ...
  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 // some cpu bound code long result = 0; for (int i = 0; i < 100; ++i) { result += i * 3; } // some blocking (I/O bound) code HttpResponse<Void> resp = httpClient.send(HttpRequest.newBuilder() .uri(URI.create(“https://myservice/test”)) .GET() .build(), BodyHandlers.discarding()); // more cpu bound code if (resp.statusCode() != 200) { ...
  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<Void> resp = httpClient.send(HttpRequest.newBuilder() .uri(URI.create(“https://myservice/test”)) .GET() .build(), BodyHandlers.discarding()); // more cpu bound code if (resp.statusCode() != 200) { ...
  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<Void> resp = httpClient.send(HttpRequest.newBuilder() .uri(URI.create(“https://myservice/test”)) .GET() .build(), BodyHandlers.discarding()); // more cpu bound code if (resp.statusCode() != 200) { ...
  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<Void> resp = httpClient.send(HttpRequest.newBuilder() .uri(URI.create(“https://myservice/test”)) .GET() .build(), BodyHandlers.discarding()); // more cpu bound code if (resp.statusCode() != 200) { ...
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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<Void> 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
  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 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 // ... }
  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 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!
  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 // ... } ThreadLocals are available for compatibility but not really useful. Do not pool VirtualThreads! ScopedValue<MyObject> SHARED_OBJECT = ScopedValue.newInstance(); ScopedValues, the better alternative to ThreadLocal are only available as preview (in JDK 21)
  86. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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; } }
  87. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  88. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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; }); } }
  89. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  90. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  91. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  92. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  93. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  94. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  95. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  96. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  97. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  98. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  99. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  100. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  101. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  102. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  103. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  104. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  105. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  106. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  107. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  108. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  109. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  110. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  111. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  112. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  113. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  114. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  115. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  116. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  117. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  118. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  119. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  120. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  121. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  122. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  123. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  124. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  125. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  126. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  127. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  128. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  129. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  130. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  131. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  132. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  133. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  134. JDK 21: Virtual Threads I/O Bound Tasks private static long

    ioBoundTask() { try { // calls a service that waits 5sec before responding… final HttpResponse<Void> 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
  135. 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(); }
  136. 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
  137. 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
  138. 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
  139. 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
  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; } // 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
  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 1. Completed in 5s
  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 1. Completed in 5s 2. Completed in 5s
  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 2. Completed in 5s
  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 2. Completed in 5s 3. Completed in 10s 4. Completed in 10s
  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 3. Completed in 10s 4. Completed in 10s
  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 3. Completed in 10s 4. Completed in 10s 5. Completed in 15s 6. Completed in 15s
  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 5. Completed in 15s 6. Completed in 15s
  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 5. Completed in 15s 6. Completed in 15s 7. Completed in 20s 8. Completed in 20s
  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 7. Completed in 20s 8. Completed in 20s
  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 7. Completed in 20s 8. Completed in 20s 9. Completed in 25s 10.Completed in 25s
  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; }); } } 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
  152. 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
  153. 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
  154. 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; }
  155. 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; }
  156. 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; }
  157. 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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  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; }
  191. 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
  192. 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
  193. 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
  194. 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
  195. 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
  196. 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
  197. 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
  198. 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)