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

More action, more overview - From 4k to 1M Threads

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

More action, more overview - From 4k to 1M Threads

Java 21+ Virtual Threads replace heavyweight platform threads with lightweight alternatives. But the real problem for teams is the migration path and how to utilize AI here.

Avatar for Merlin Bögershausen

Merlin Bögershausen

March 10, 2026
Tweet

More Decks by Merlin Bögershausen

Other Decks in Programming

Transcript

  1. ©2025 Moderne, Inc. Who sees a problem? Quick POLL POLL

    2 for (int i = 0; i < 1_000_000; i++) { } new Thread(() -> processOrder()).start();
  2. ©2024 Moderne, Inc. 18 The Money Slide 1 MB per

    Thread ~ 10.000 Threads max 1 ms creation time 1 KB per Thread 1.000.000+ Threads possible Created in 1 μs 1000 x 100 x 1000 x Platform Thread Virtual Thread Impact https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html https://www.infoq.com/articles/java-virtual-threads-a-case-study/ https://github.com/ebarlas/java-httpserver-vthreads
  3. ©2024 Moderne, Inc. 5 Rule Engine Example class Engine {

    interface Rule { void fire(); } void execute(List<Rule> rules, Map<String, String> data) {} } Rule Engine with 100.000 Rules executed in parallel GitHub GIST
  4. ©2024 Moderne, Inc. 7 Java Thread - Basics // Platform

    Thread = OS Thread = 1MB new Thread(() -> doWork()).start(); // Workaround: Thread Pools, ... Executors.newFixedThreadPool(100);
  5. ©2024 Moderne, Inc. 8 Virtual Threads – Java 21 for

    (int i = 0; i < 1_000_000; i++) { // 1 Virtual Thread = 1KB Thread.startVirtualThread(() -> doWork()); } // Retrofit to Executors try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { IntStream.range(0, 1_000_000) .forEach(i -> executor.submit(() -> doWork())); }
  6. ©2024 Moderne, Inc. 10 Virtual Threads Architecture Virtual Thread Carrier

    Thread OS Thread 1 KB Heap ForkJoinPool 1 MB Stack Platform Thread OS Thread loose 1:1 1:1
  7. ©2024 Moderne, Inc. 11 • I/O-bound operations DB, REST calls

    • High concurrency >1000 concurrent tasks • Request-per-thread model Great us if When to Use Virtual Threads • CPU-intensive calculations • Thread pools (NEVER pool Virtual Threads!) Avoid for
  8. ©2024 Moderne, Inc. 14 Scoped Values API // JEP 506

    - Final in Java 25! private static final ScopedValue<SSLContext> SSL_CTX = ScopedValue.newInstance(); private static final ScopedValue<Map<String, String>> CONTEXT = ScopedValue.newInstance(); // set and pass ScopedValue.where(SSL_CTX, sslContext) .where(CONTEXT, data) .run(() -> processWithContext());
  9. ©2024 Moderne, Inc. 15 • Mutable data • Not memory

    Save • Copy per (virtual) Thread • Slower due to Implementation ThreadLocal What about ThreadLocal • Immutable Data • Memory Save • Designed for Virtual Threads • Efficient Implementation ScopedValue
  10. ©2024 Moderne, Inc. 18 StructuredTaskScope API try (var scope =

    StructuredTaskScope.open()) { Subtask<String> task = scope.fork(() -> doWork()); scope.join(); // void return return task.get(); //Exception on failure }
  11. ©2024 Moderne, Inc. 19 Concurrent Rule void fire() { try

    (var scope = StructuredTaskScope.open()) { Subtask<String> name = scope.fork(() -> readName()); Subtask<Address> address = scope.fork(() -> readAddress()); scope.join(); System.out.printf("%s's home is %s %d, %s%n", name.get(), address.get().street(), address.get().house(), address.get().city()); } catch (InterruptedException e) { throw new RuntimeException(e); } }
  12. ©2024 Moderne, Inc. 21 How many SSLContexts class Rule {

    final SSLContext sslContext = SSLContext.getDefault(); }
  13. ©2024 Moderne, Inc. 22 How many SSLContexts class Rule {

    SSLContext sslContext; SSLContext fire() { // if null create than return } }
  14. ©2024 Moderne, Inc. 23 Now we are down to 1!

    class Rule { final static LazyConstant<SSLContext> sslContext = LazyConstant.of(() -> { try { return SSLContext.getDefault(); } catch (Exception e) { throw new RuntimeException(e); } }); }
  15. ©2024 Moderne, Inc. 26 Path to Migrate 1. Virtual Threads

    (Final seit Java 21) → migrate if I/O-bound workloads 2. Scoped Values (Final in Java 25) → ThreadLocal replace where immutable, use recipe 3. Structured Concurrency (Sixth Preview) → experiment and feedback; not in prod, yet 4. Lazy Constants (Preview in Java 25 & 26) → Check for lazy initialization Pro tip: Use tools to Understand surface
  16. ©2024 Moderne, Inc. 27 Best Practices Thread.startVirtualThread() Executors.newVirtualThreadPerTaskExecutor() ScopedValues für

    immutable context A million Virtual Threads is fine! NEVER pool Virtual Threads No ThreadLocals with Virtual Threads Not for CPU-intensive Tasks Pro tip: Use tools to Understand surface === Combined total === Uses: 105 Input: 177 Output: 21,306 Cache create: 276,238 Cache read: 2,135,980 Total tokens: 2,433,701 === Combined total === Uses: 12 Input: 22 Output: 1,794 Cache create: 11,291 Cache read: 203,578 Total tokens: 216,685 Propper Tools
  17. ©2024 Moderne, Inc. 28 Resources Code & Examples: github.com/MBoegers/87fa0928c46e037155dbc7d48aaf7553 github.com/MBoegers/openrewrite-misc-recipes

    docs.moderne.io/user-documentation/agent-tools/trigrep Compile & Run: javac --release 26 --enable-preview *.java java --enable-preview Main JEPs: • JEP 444: Virtual Threads (Final) • JEP 506: Scoped Values (Final) • JEP 525: Structured Concurrency (Preview) • JEP 526: Lazy Constants (Preview) GitHub GIST