Skip to main content

What's new in Java 21: A Tour of its Most Exciting Features

The Java platform now follows a six-month release cycle, and Java 21 has succeeded Java 17 as the most recent long-term support release (LTS).

JDK 21 features a total of 15 JEPs (JDK Enhancement Proposals). You can view the complete list on the official Java site here. In this document, I'll highlight several Java 21 JEPs that I find particularly noteworthy.

1) Sequenced collections

Java 21 introduces a new Java Collection Hierarchy, enhancing operations on ordered datasets. This new API not only facilitates convenient addition and deletion of the first and last elements of a collection but also enables reversing sequences.

2) Pattern Matching for switch

Pattern Matching for switch builds upon the extended instanceof expression.

Before Java 21

In Java 21

Pattern Matching

Pattern Matching using When

3) Record Patterns

Record patterns are a new feature, first introduced in Java 19 as a preview.

Before Java 21

In Java 21

Record Patterns

Nested Record Patterns


3) Virtual Threads

The Virtual Threads feature is the most exciting addition in Java 21.

Why Virtual Threads ?

We can estimate that a single java.lang.Thread consumes approximately 2 to 8 MB of memory, depending on the OS and configuration. Additionally, each Java Thread is mapped 1:1 to a kernel thread. In simple web applications that use a "one thread per request" approach, this can quickly overwhelm/kill our server when traffic increases.

Thread-4059 is running
        Thread-4060 is running
        [0.751s][warning][os,thread] Failed to start thread "Unknown thread" - pthread_create failed (EAGAIN) for attributes: stacksize: 1024k, guardsize: 4k, detached.
        [0.751s][warning][os,thread] Failed to start the native thread for java.lang.Thread "Thread-4061"
        Exception in thread "main" java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached
        at java.base/java.lang.Thread.start0(Native Method)
        at java.base/java.lang.Thread.start(Thread.java:802)
        at tb.NoVirtualThreads.main(NoVirtualThreads.java:19)

        Process finished with exit code 1

Running Virtual Threads ?

Virtual Threads are not managed or scheduled by the operating system; instead, their scheduling is handled by the JVM. While actual tasks need to be executed, the JVM uses carrier threads, which are essentially platform threads, to execute any virtual thread when it's ready.

Virtual Threads are designed to be lightweight and consume significantly less memory than standard platform threads.

.
.
.
[VirtualThread[#1000039,virtual-thread-999981]/runnable@ForkJoinPool-1-worker-13]
[VirtualThread[#1000041,virtual-thread-999983]/runnable@ForkJoinPool-1-worker-9]
[VirtualThread[#1000043,virtual-thread-999985]/runnable@ForkJoinPool-1-worker-13]
[VirtualThread[#1000046,virtual-thread-999988]/runnable@ForkJoinPool-1-worker-9]
[VirtualThread[#1000048,virtual-thread-999990]/runnable@ForkJoinPool-1-worker-13]
[VirtualThread[#1000051,virtual-thread-999993]/runnable@ForkJoinPool-1-worker-9]
[VirtualThread[#1000053,virtual-thread-999995]/runnable@ForkJoinPool-1-worker-13]
.
.
.

ForkJoinPool-1-worker-X platform threads serve as carrier threads that manage our virtual threads. We observe that virtual threads numbered 999981, 999985, 999990, and so on, are all using the same carrier thread, number 13.

When a virtual thread encounters a blocking operation, such as an I/O task, the JVM efficiently detaches it from the underlying physical thread (the carrier thread). This detachment is crucial because it frees up the carrier thread to run other virtual threads instead of remaining idle, waiting for the blocking operation to finish.

Consequently, a single carrier thread can multiplex many virtual threads, potentially numbering in the thousands or even millions, depending on available memory and the nature of the tasks.

Note: Virtual threads are not the only way to handle this problem. Asynchronous programming (using frameworks like WebFlux or native Java APIs like CompletableFuture) is another approach.


4) String Templates (Preview)

The Spring Templates feature remains in preview mode. To utilize it, you need to include the "--enable-preview" flag in your compiler arguments.

Before Java 21

In Java 21

5) Generational ZGC

Enhance application performance by enhancing the Z Garbage Collector (ZGC) to manage separate generations for young and old objects. This enhancement enables ZGC to collect young objects—commonly short-lived—more frequently.

ZGC was initially introduced into JDK 11 as an experimental garbage collector (GC) implementation. Subsequently, with the implementation of JEP-377, it transitioned into a production-ready feature in JDK 15.

In essence, ZGC aims to minimize stop-the-world phases to the greatest extent possible. It achieves this by ensuring that the duration of these pause times remains independent of the heap size. These attributes make ZGC well-suited for server applications, particularly those with large heaps where rapid application response times are crucial.

You can find further information on memory management in Java here, Garbage collector basics here, and learn more about ZGC here.

6) Other Features

In addition to the previously mentioned features, Java 21 also introduces several additional preview features:

1) Foreign Function & Memory API (Third Preview) (https://openjdk.org/jeps/442)
2) Unnamed Patterns and Variables (Preview) (https://openjdk.org/jeps/443)
3) Unnamed Classes and Instance Main Methods (Preview) (https://openjdk.org/jeps/445)
4) Scoped Values (Preview) (https://openjdk.org/jeps/446)
5) Vector API (Sixth Incubator) (https://openjdk.org/jeps/448)

And few others as well.

Comments

Popular posts from this blog

Deploying Spring Boot microservices on Kubernetes Cluster

This article guides you through the deployment of two Spring Boot microservices, namely "order-service" and "inventory-service," on Kubernetes using "MiniKube" . We will establish communication between them, with "order-service" making calls to an endpoint in "inventory-service." Additionally, we will configure "order-service" to be accessible from the local machine's browser . 1) Create Spring Boot microservices The Spring Boot microservices, "order-service" and "inventory-service," have been developed and can be found in this GitHub repository. If you are interested in learning more about creating Spring Boot REST microservices, please refer to this or this (Reactive) link. 2) Build Docker Images The Docker images for both "order-service" and "inventory-service" have already been generated and deployed on DockerHub, as shown below. codeburps/order-service cod...

Circuit Breaker Pattern with Resilience4J in a Spring Boot Application

Read Also: Spring Cloud Circuit Breaker + Resilience4j Resilience4j is a lightweight fault tolerance library that draws inspiration from Netflix Hystrix but is specifically crafted for functional programming. The library offers higher-order functions, known as decorators , designed to augment any functional interface, lambda expression, or method reference with features such as Circuit Breaker, Rate Limiter, Retry, or Bulkhead . These functionalities can be seamlessly integrated within a project, class, or even applied to a single method. It's possible to layer multiple decorators on any functional interface, lambda expression, or method reference, allowing for versatile and customizable fault tolerance. While numerous annotation-based implementations exist online, this article focuses solely on the reactive approach using router predicates and router functions . How Circuit Breaker Pattern works? In general, a circuit breaker functions as an automatic electrical s...

Declarative REST Client in Spring Boot (Spring 6 HTTP Interface)

Feign , an early declarative REST client, was initially part of the Spring Cloud Netflix stack and later rebranded as Spring Cloud OpenFeign . Before its introduction, crafting HTTP calls using RestTemplate involved repetitive code for each service interaction. With Feign, developers could simply define an interface with method contracts mirroring the service's endpoints. Behind the scenes, proxy magic generated a fully functional HTTP client, eliminating the need for boilerplate code . HTTP Interface (Spring Framework 6) The recent release of Spring Framework 6 integrated this declarative REST client as a native part of the core web framework in the form of the HTTP Interface . All the necessary components reside in the spring-web module, which is a transitive dependency for either the spring-boot-starter-web or spring-boot-starter-webflux modules. Currently, the WebFlux dependency is essential due to the HttpServiceProxyFactory , responsible for client gener...