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

  • 4.6/5
  • 3695
  • Jul 20, 2024

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.

Index
Modern Java - What’s new in Java 9 to Java 17

32 min

What is differences between JDK, JVM and JRE ?

2 min

What is ClassLoader in Java ?

2 min

Object Oriented Programming (OOPs) Concept

17 min

Concurrency in Java: Creating and Starting a Thread

12 min

Concurrency in Java: Interrupting and Joining Threads

5 min

Concurrency in Java: Race condition, critical section, and atomic operations

13 min

Concurrency in Java: Reentrant, Read/Write and Stamped Locks

11 min

Concurrency in Java: "synchronized" and "volatile" keywords

10 min

Concurrency in Java: using wait(), notify() and notifyAll()

6 min

Concurrency in Java: What is "Semaphore" and its use?

2 min

Concurrency in Java: CompletableFuture and its use

18 min

Concurrency in Java: Producer-consumer problem using BlockingQueue

2 min

Concurrency in Java: Producer-Consumer Problem

2 min

Concurrency in Java: Thread pools, ExecutorService & Future

14 min

Java 8 Lambdas, Functional Interface & "static" and "default" methods

28 min

Method Reference in Java (Instance, Static, and Constructor Reference)

9 min

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

14 min

Java Memory Leaks & Heap Dumps (Capturing & Analysis)

9 min

Memory footprint of the JVM (Heap & Non-Heap Memory)

15 min