This month we are focusing our articles on various OpenJDK projects that are currently in development.
So far we have already covered Projects Valhalla, Panama, Skara and Amber. This week we will be looking at Project Loom and detailing what it is, how it differs from existing Threads and the current progress of the project.
What is Project Loom?
Project Loom is the development of lightweight concurrency for the Java Runtime. The goal is to make it possible to write synchronous blocking code that is simple to use and still scalable. Traditionally synchronous blocking code can be a lot less scalable than asynchronous code. Project Loom hopes to address this.
Project Loom intends to add 3 new constructs: Continuations, Fibers and Tail-Calls.
These are program objects representing a computation that may be suspended and resumed. This translates to is a subroutine that can execute a computation and may be stopped and then continued, continuing from a given entry point with its state from that point intact.
A lightweight or user mode thread. Fibers are scheduled by the JVM and not the operating system. Being scheduled by the JVM can allow Fibers to have a low footprint and minimal overhead when switching tasks. This allows us to have have larger quantities of Fibers with decreased overhead and improved scalability.
Currently not implemented. The team “envision tail-call elimination that pops one or perhaps even an arbitrary number of stack frames at explicitly marked call-sites. It is not the intention of this project to implement automatic tail-call optimization.”
The way these are intended to work together is via a Scheduler that executes the Fibers on a pool of carrier Threads. The scheduler does the heavy lifting of handling OS threads, the fibers can run on any of these threads to be executed. When a Fiber yields the carrier thread will execute another Fiber instead.
How do Fibers differ to Threads?
Fibers and Threads in Java can be thought of in very similar ways. A Fiber is a Thread, a Continuation is a Runnable. However the differences are in how they are managed. Fibers run on a carrier thread which but does not block when a Fiber blocks. Instead when a Fiber blocks the thread stops executing the Fiber and becomes free for the scheduler to pass it a new Fiber to execute. By using Fibers in this way we can avoid the overhead involved by doing the same thing running multiple threads.
For example, with a synchronousQueue you could have two fibres or threads. One that adds a series of values to the queue and one that takes a series of values. As the queue has no capacity the fibres / threads will block after adding or taking a single value from the queue. The two fibers / threads would need to swap execution. However the fibers are running on the same carrier thread so instead of swapping threads we just pass the thread to the other Fiber to execute which is must faster. This also has the benefit of minimizing the number of threads needed by the application.
There are currently some limitations to Fibers. For instance, Fibers can’t yield with native frames on a continuation stack or whilst holding a monitor (such as from Synchronise) as they pin the carrier thread. Also Object.wait may park the carrier thread. However this project is still in development so we can expect to see improvements in these areas.
Current progress of Project Loom?
The project is still in development and will not be put forward until the feature set is complete. The project in its current state has initial prototypes for Continuation and Fiber objects.
The current focus of the project is performance, the Fiber API and Debugger support. The footprint of fibers compared to Threads is also looking promising.
Foot print as reported at Devoxx Belgium:
Thread ~ 1.0183 MB per Thread
Fiber (prototype) ~230 bytes per Fiber
If you wish to download and build project loom details are provided on the OpenJDK Wiki page which I have linked below.