The nearest JDK 19 release is associated with a major event in the Java world — the introduction of virtual threads. It means that Java will get its own lightweight concurrency model, just like other modern programming languages. But there is still a lot of work to enhance and strengthen this feature. JEP 429: Extent-Local Variable targeted for Java 20 as an Incubator API is part of this effort.
Motivation behind the JEP
Thread-local variables have been a traditional way of sharing data between application components without using method arguments. They represent the ThreadLocal type and are usually declared as final static
fields. They have multiple (one per thread) incarnations: code in each thread reads and writes its own distinct incarnation.
These variables have inherent disadvantages: they are mutable and have an unbound lifetime and large overhead. The memory footprint increases with the number of threads used. Since newly introduced virtual threads can be quite plentiful (thousands or millions), memory consumption will be significant. Therefore, Java needs new per-thread variables to avoid costs of thread-local variables and increase the reliability of data flow in multithreaded applications. They must be immutable so that the child threads can efficiently share the data. They should also have a bounded lifetime to reduce the risk of memory leaks.
Description
Extent-local variables belong to the ExtentLocal type and have multiple incarnations, just like thread-local variables. But unlike their counterparts, extent-local variables are written once and then become immutable and available only during the thread’s execution.
The name is derived from the “expect” concept used in the JVM specification. A method m1 in a given thread invokes a method m2, which invokes a method m3, and so on. While the methods haven’t been completed, their frames are stored in the JVM stack, where they are collectively called an extent. Extent-local variables written in m1 can be read in m2, m3, etc.
The following code snippet demonstrates the usage of extent-local variables.
final static ExtentLocal<...> V = new ExtentLocal<>();
// In some method
ExtentLocal.where(V, <value>)
.run(() -> { ... V.get() ... call methods ... });
// In a method called directly or indirectly from the lambda expression
... V.get() ...
Note that the code structure delineates the period when a thread can read the incarnation of a variable. In addition, there is one-way data transmission from caller to callees. The absence of set()
method means no remote code in the stack can change the variable, and the data can be reliably communicated to callees in the same thread. Immutability also increases the performance because an extent-local variable with get()
is read as fast as a local variable.
Extent-local variables will be helpful in many scenarios where thread-local variables are used now, especially when reliable one-way transmission of immutable data is essential.
But there are several use cases where migration to extent-local variables is not preferable. For instance, when the data is transmitted in two ways (via set()
method from one callee to another) or when code uses DateFormat objects, which are mutable per se.
Conclusion
The release of Java 20 is six months away, but the work on enhancing concurrency in Java is ongoing, so we are looking forward to news about other features targeted for the next release. Subscribe to our newsletter to stay tuned!
Subscribe to newsletter