Using Project Loom to Improve Java Web App Concurrency

Published: June 18, 2023


Concurrency is a cornerstone of modern web applications. Handling many simultaneous requests efficiently without complicating the codebase is a major challenge for Java developers. Enter Project Loom, an ambitious effort to revolutionize concurrency in Java by introducing virtual threads—lightweight threads managed by the JVM.

In this post, we’ll explore how Project Loom works, how virtual threads can improve your Java web applications, and practical tips to get started.


What is Project Loom?

Traditional Java concurrency uses OS threads that are relatively heavy, expensive to create and manage. While frameworks like Reactive programming address scalability by avoiding blocking calls, they introduce complexity and a steep learning curve.

Project Loom adds virtual threads, which are:

  • Lightweight: Millions can run concurrently without bogging down resources.
  • Easy to use: Programming model stays simple, just like using normal threads.
  • Compatible: Existing blocking APIs (like JDBC, Servlet) can be used without change.

Virtual threads aim to make writing highly concurrent applications as simple as writing sequential code.


Why Virtual Threads Matter for Web Apps

Web servers handle thousands of requests concurrently. Traditionally, each request is assigned to an OS thread, which limits scalability because threads consume system resources. Reactive models can handle this better but are complex.

With Loom:

  • You can write synchronous-style code that scales like asynchronous code.
  • Block on IO (database calls, network, etc.) without worrying about starving thread pools.
  • Simplify code maintenance and readability.

Using Virtual Threads with Java Web Servers

Let’s say you have a simple web server handling requests:

Without Loom (traditional):

ExecutorService executor = Executors.newFixedThreadPool(100);

server.handle(request -> {
  executor.submit(() -> {
    // blocking IO call, e.g., database query
    String data = database.query(request.getParam());
    response.send(data);
  });
});

Here, you’re limited to 100 concurrent threads.

With Loom virtual threads:

ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

server.handle(request -> {
  executor.submit(() -> {
    // blocking IO call, same code but runs on virtual thread
    String data = database.query(request.getParam());
    response.send(data);
  });
});

Now you can handle tens of thousands of concurrent requests because each request uses a lightweight virtual thread.


Code Example: Simple HTTP Server with Virtual Threads

Java 19+ includes a minimalistic HTTP server API that you can combine with virtual threads:

import java.net.http.HttpServer;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

public class VirtualThreadHttpServer {
  public static void main(String[] args) throws Exception {
    var server = HttpServer.create(new InetSocketAddress(8080), 0);

    var executor = Executors.newVirtualThreadPerTaskExecutor();
    server.setExecutor(executor);

    server.createContext("/", exchange -> {
      String response = "Hello from Virtual Thread: " + Thread.currentThread();
      exchange.sendResponseHeaders(200, response.getBytes().length);
      exchange.getResponseBody().write(response.getBytes());
      exchange.close();
    });

    server.start();
    System.out.println("Server started on http://localhost:8080");
  }
}

Run this with:

java --enable-preview --source 19 VirtualThreadHttpServer.java

This server can handle thousands of connections with minimal resource use.


Migrating Existing Apps

One great thing about Project Loom is backwards compatibility. You don’t need to rewrite your app to use virtual threads.

  • Replace your thread pools with Executors.newVirtualThreadPerTaskExecutor().
  • Keep using synchronous APIs without blocking the OS threads.
  • Over time, refactor blocking operations for maximum benefit.

Limitations and Current State

  • Virtual threads are still in preview (Java 19, 20, 21).
  • Some libraries might need updates for full compatibility.
  • Performance is promising but continue benchmarking for your workload.

Summary

BenefitDescription
Simplified concurrencyWrite simple blocking code, scalable concurrency
Lightweight threadsMillions of virtual threads possible
Backwards compatibleUse with existing blocking APIs

Conclusion

Project Loom is a game-changer for Java web app concurrency, promising to combine the simplicity of traditional threading with the scalability of modern async paradigms. While still evolving, it’s worth experimenting with Loom in your next project or migration.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *