The Loom project will add virtual threads to Java 19. What’s this? New prospects for the labor market emerge in the previous post. In terms of JVM internals, Ivan Ugljansky talks about Loom: I recommend his report “Thread Wars – Project Loom Strikes Back“.
Here we will evaluate how the addition will affect modern server development approaches. Will the novelty push Scala and Kotlin with their frameworks? At the same time, we will answer the question “to what extent is Loom reactive”?
Vert.x and Loom
From the point of view of Vert.x, the new addition to Java is not a competing framework, but an engine. Now Vert.x uses Netty as its engine. What will Vert.x gain by switching to Loom? Variable stack traces. They will greatly simplify debugging and maintaining a reactive application. The developers of Vert.x are well aware of this. The project already has separate branch for integration with Loom.
Spring and Loom
Let’s give a word to the Spring developers:
The first thing that comes to my mind is spring-web*. Implementations [на базе] WebMvc is concrete and simple, while implementations [на базе] WebFlux is scalable and reactive. The latter comes with the disadvantages of code complexity, poor readability, and poor debugging capability. Loom, on the other hand, promises to achieve scalability by spawning millions of Fibers, while at the same time keeping the code readable while keeping its organization consistent.
– This research task was included in the Spring version 6 checkpoint immediately after Loom was announced in JDK 19.
Reactivity and Loom
Jonas Boner Manifesto (2014) defines the Reactive System as:
Responsive: Responds as quickly as possible.
Resilient: copes with failures and does it herself.
Elastic: automatically increases and decreases resource consumption depending on the load. Elasticity includes scaling.
Message Driven: Relies on asynchronous message processing which, among other things, provides backpressure and forms monitored message queues. Message communication is non-blocking.
Note that the last point is a technological solution from which the first three follow. And at the same time, the “stack trace, goodbye” item, which for some reason they forgot to add to the manifest.
In the case of Loom, the technical solution is not messaging, but lightweight streams (or fibers, or goroutines). Strictly speaking, according to Boner, Loom is non-reactive. At the same time, it processes messages in an asynchronous and non-blocking manner. With it, you can ensure the responsiveness and scalability of the system, as Spring developers rightly point out. From the reactive gentleman’s set, the project lacks back pressure and an analogue of monitored queues.
Back pressure is needed to cope with an uneven load. Third party libraries like Vert.x can help with the implementation.
Queues are needed to keep track of changing load. A couple of years ago, project tech lead Ron Presler mentioned that Doug Lee has already started channel development (non-blocking queues). However, the results are not visible in any JEP yet.
We summarize that in a practical sense, Loom has the properties of a reactive system or solves its problems.
Loom and next generation reactivity
Earlier this year, Daniel Spivak (Disney Principal Engineer) put forward the thesis that he created next generation reactive framework. Daniel rightly notes that reactivity is usually associated with the management of system threads – indeed a very expensive and limited OS resource. However, there are other types of reserves, the number of which is limited. You need to dispose of them very carefully, otherwise the application will stop working stably.
The special language construct try-with-resources appeared in Java 7. The problem is that this mechanism does not work in asynchronous mode.
scala library Cats Effect 3 authorship of Spivak introduces additional resource management primitives.
And with them you can write, for example, racing code:
val uri1 = “jdbc:postgress:replica1”
val uri2 = “jdbc:postgress:replica2”
val joint: Resource[IO, Connection] =
In this case, there is a simultaneous connection to two replicas of the database. As a result, further code will use the faster connection. The latecomer will be correctly finalized and the resources associated with it will be freed.
An important scenario that triggers resource release is request cancellation. First, at the request of the client, the server is required to perform some actions. In the process of performing actions, a cancel signal is received. A request can be canceled by the client, by a timeout, and even by a system failure.
Next-generation reactivity provides first-class support for:
guaranteed release of resources;
cancellation of asynchronous operations with the release of resources;
in particular, timeout stops.
If we look into Vert.x or Spring WebFlux, we won’t find anything like that. Why? Because neither the libraries on which these frameworks are based, nor Java itself provide primitives on whose basis it would be possible to build the necessary operations or methods.
Will the Loom project help with this? Under JEP 425, no. And here is the accompanying JEP 428 describes Structural Concurrency (SC) as a new addition in Java 19.
The SC approach has been implemented on a wide variety of platforms. For example, in the library Kotlinovskih coroutines. In short, SC provides an alternative to primitives Cats Effect 3 a way to manage resources while organizing code asynchronously. Cancellations and timeouts are also possible there. For now, JEP 428 focuses solely on thread management.
We see that Java developers are aiming to give the language the ability to build next-generation reactive-level systems. While these intentions are at the stage of incubation. It remains an open question whether high-level frameworks (Vert.x, Spring, and so on) will be able to rely on new basic primitives. As the creator of Java, James Gosling, observed, “It’s not easy to come up with semantics that work well.”
Changes are coming to Java that will allow, on the one hand, to implement responsive and scalable systems, and, on the other hand, to make it easier to maintain asynchronous code. This process has just begun. Today, for a new project based on the JDK, it would be better to choose something like Cats Effect 3 or Kotlin’s coroutines. Java intends to compete with them, but sometime in the distant future and with an as yet unclear result.
In the next part of the note, we are migrating the toy project to Loom. Let’s see how much effort it will require and what exactly has changed as a result.