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

Project Loom: Broadening Concurrency

Mark Paluch
September 23, 2022

Project Loom: Broadening Concurrency

Project Loom has landed in Java 19 as a preview feature. It promises to simplify concurrency the way garbage collection simplifies memory management and improves applications' scalability.

It's about time to closely examine the value proposition and how it is implemented to understand what Loom can provide for your application. We will dive into technical details to understand concurrency, look at examples of how they behave, and how we can debug virtual thread code. You will learn what to watch out for and how project Loom can help you to write simple, concurrent code to get the most out of your runtime environment.

Mark Paluch

September 23, 2022
Tweet

More Decks by Mark Paluch

Other Decks in Programming

Transcript

  1. Project Loom
    Broadening Concurrency

    View full-size slide

  2. Mark Paluch
    Spring Data Project Lead @ VMware
    R2DBC Spec Lead
    Lettuce Redis Driver Maintainer
    Paramedic & SAR Dogs

    View full-size slide

  3. Sept 2020, https://paluch.biz/blog/182-experimenting-with-project-loom-eap-and-spring-webmvc.html
    „We’ve been there, already“

    View full-size slide

  4. Tomcat + Virtual Threads Tomcat + Kernel Threads

    View full-size slide

  5. What is Project Loom
    • Initiative to introduce virtual threads to the Java Platform. Virtual threads are
    lightweight threads that dramatically reduce the effort of writing, maintaining,
    and observing high-throughput concurrent applications.

    View full-size slide

  6. What is Project Loom
    • Initiative to introduce Introduction of virtual threads and concurrency API to
    the Java Platform. Virtual threads are lightweight threads that eliminate I/O
    wait. dramatically reduce the effort of writing, maintaining, and observing
    high-throughput concurrent applications.

    View full-size slide

  7. What Project Loom actually is
    • Introduction of virtual threads and concurrency API to the Java Platform.
    Virtual threads are lightweight threads that eliminate I/O wait.

    View full-size slide

  8. Dramatically reduce the effort of writing,
    maintaining, and observing concurrent applications
    • True if you run on a Virtual Thread

    • Future.get(), Thread.sleep(), Lock.lock() are good friends again

    • No need for future chaining, using complex reactive or asynchronous API

    • Not so, if you accidentally run on a Kernel Thread

    View full-size slide

  9. Platform Thread
    • Renamed from Kernel Thread

    • new Thread(…)

    View full-size slide

  10. Virtual Thread
    • Package-private subtype of java.lang.Thread

    • Provides customized behavior

    • Subject to be executed on carrier Thread

    View full-size slide

  11. Carrier Threads
    • Separate Fork/Join Pool of Platform Threads

    • Default size: Runtime.availableProcessors()

    • Configurable through system properties
    (jdk.virtualThreadScheduler.parallelism, maxPoolSize,
    minRunnable)

    View full-size slide

  12. Virtual Threads API
    • Extended Thread API

    Thread.ofVirtual().start(() -> {…});
    Executors.newVirtualThreadPerTaskExecutor()
    Thread.currentThread().isVirtual()
    • Implemented almost entirely in Java

    View full-size slide

  13. try(var e = Executors.newVirtualThreadPerTaskExecutor()){
    for (int j = 0; j < 100; j++) {
    e.execute(() -> Thread.sleep(100));
    }
    } // implicit wait

    View full-size slide

  14. Parking & Unparking
    • On each blocking operation

    • If blocked, capture stack and store it

    • Carrier thread free to perform other work (unpark next virtual thread)

    View full-size slide

  15. Blocking in synchronized code
    • Leads to Carrier Thread Pinning

    • Carrier Thread bound to virtual thread until unblock

    • synchronized is a JVM behavior, cannot be controlled from Java code

    • I/O, Locks, Future.get() in synchronized leads to Thread Pinning

    View full-size slide

  16. Thread Type Selection
    • I/O-heavy, shared-resources with Java Locks, Concurrency Utils

    • Virtual Threads

    • Computation-heavy, synchronized workloads

    • Platform Threads

    View full-size slide

  17. Observability, Tooling, Trouble Shooting
    • Java Flight Recorder Events

    • Virtual Thread start/end, pinned, submission failed

    • Debugging: IntelliJ announced tooling support for later this year

    • Pinned thread monitoring

    • -Djdk.tracePinnedThreads=full|short

    View full-size slide

  18. Virtual Thread Usage

    View full-size slide

  19. Usage of Virtual Thread API
    • In every piece that could block or wait in Java

    • Thread.sleep

    • Locks, ConcurrentHashMap

    • I/O (Socket)

    • Rewrite of several components as pre-requisite for Loom to avoid thread pinning

    View full-size slide

  20. Usage Pattern
    • Kernel Threads („Platform Threads“)

    • Expensive

    • Thread Pooling

    • Virtual Threads

    • Cheap

    • New Virtual Thread per Runnable

    View full-size slide

  21. JMH Benchmarks
    Benchmark Mode Cnt Score Error Units
    VirtualThreadsBenchmark.createVirtualThreads thrpt 5 14488555,637 ± 1127513,241 ops/s
    VirtualThreadsBenchmark.runAndAwait thrpt 5 455494,235 ± 22033,286 ops/s
    PlatformThreadsBenchmark.createPlatformThreads thrpt 5 19094,736 ± 677,739 ops/s
    PlatformThreadsBenchmark.runAndAwait thrpt 5 15807,802 ± 7337,906 ops/s

    View full-size slide

  22. JMH Benchmarks
    Benchmark Mode Cnt Score Error Units
    VirtualThreadsBenchmark.createVirtualThreads thrpt 5 14488555,637 ± 1127513,241 ops/s
    VirtualThreadsBenchmark.runAndAwait thrpt 5 455494,235 ± 22033,286 ops/s
    PlatformThreadsBenchmark.createPlatformThreads thrpt 5 19094,736 ± 677,739 ops/s
    PlatformThreadsBenchmark.runAndAwait thrpt 5 15807,802 ± 7337,906 ops/s
    ThreadPoolExecutorBenchmark.runAndAwait thrpt 5 461335,862 ± 54427,010 ops/s

    View full-size slide

  23. What does that mean?
    • If the CPU availability is the limit: You cannot increase concurrency

    • If the Runnable wait is the limit: You can increase concurrency

    View full-size slide

  24. Loom Overhead
    • Hard to say. What’s the typical application?

    View full-size slide

  25. Scalability Boundaries
    • I/O in synchronized Code

    • Connection Pool Sizes

    • Databases

    • HTTP/JMS/… Connection Pools

    • File handles

    • number of open files

    View full-size slide

  26. Pitfalls
    • System.out.println(…)
    • Attempts to obtain a lock on the I/O

    • Measurement and benchmark correctness („What do you measure?“)

    • Visible and invisible Thread Pinning

    View full-size slide

  27. Client/Server Workloads
    • Workload to be served by virtual thread (carrier threads must be available)

    • System must have sufficient resources to serve the request (e.g. connection
    pools). Also a constraint for platform thread usage.

    • Request to server via I/O

    • During wait, virtual thread is parked

    • Client must not pin kernel thread (see carrier thread availability)

    View full-size slide

  28. Computation Workloads
    • Incoming request/event to be served by virtual thread (carrier threads must be
    available)

    • System performs a computation based on in-memory resources

    • Response is returned

    View full-size slide

  29. Call to Action
    • Investigate: What is limiting your application scalability?

    • Investigate: What workloads do you run?

    • Experiment: Run your application on Virtual Threads and benchmark it!

    • Observe: What libraries lead to thread pinning?

    View full-size slide

  30. Maybe.
    „Will Loom help with concurrency and
    scalability in my app?“

    View full-size slide

  31. Thank You.
    github.com/mp911de
    @mp911de
    paluch.biz

    View full-size slide