Stable Release in branch Java SE 21 (LTS)
21.0.11
Released 21 Apr 2026
(2 months ago)
SoftwareJava/Java SE
VersionJava SE 21 (LTS)
StatusLTS
Supported
Class file version65.0
Initial release21
19 Sep 2023
(2 years ago)
Latest release21.0.11
21 Apr 2026
(2 months ago)
End of
premier support
Sep 2028
(Ends in 2 years, 2 months)
End of
extended support
Sep 2031
(Ends in 5 years, 2 months)
Release noteshttps://www.oracle.com/java/technologies/javase/21-0-11-relnotes.html
Documentationhttps://docs.oracle.com/javase/21
Downloadhttps://www.oracle.com/java/technologies/javase/jdk21-archive-downloads.html
Java/Java SE Java SE 21 (LTS) ReleasesView full list

What Is New in Java 21

Java 21 is a Long-Term Support (LTS) release that delivers a substantial set of production-ready features alongside several finalized language enhancements, making it the most significant LTS since Java 17. The release covers the initial GA build through the latest patch update, JDK 21.0.11.

Category Highlights
New Features Virtual Threads (JEP 444), Generational ZGC (JEP 439), Sequenced Collections (JEP 431), Record Patterns (JEP 440), Pattern Matching for switch (JEP 441), Key Encapsulation Mechanism API (JEP 452), Math.clamp(), String.indexOf() with range, HttpClient AutoCloseable, JFR view command, G1 GCOverheadLimit support, configurable TLS session tickets
Improvements G1 full GC now moves humongous objects to prevent OOM, enhanced OCSP/CRL/cert fetch timeouts, JAXP configuration file overhaul, javac this-escape warning, JShell TOOLING script, StringBuilder/StringBuffer repeat(), keytool password handling hardened, JSSE/JCE source code now in src.zip, new jdk.crypto.disabledAlgorithms property
Bug Fixes Cgroup v1/v2 container detection overhaul (Linux), SSLSocket output record buffer miscalculation, reflective invocation performance regression in native methods, mouse handling broken on XWayland GNOME 47+, G1 TLAB allocation GC disallowed correctly, C2 Long assertion crash fixed
Breaking Changes java.lang.Compiler class removed, JAR Index feature removed, java.io.File canonical path cache removed (and related system properties), RMIIIOPServerImpl removed, G1 Hot Card Cache removed, -XX:+EnableWaitForParallelLoad option removed
Deprecations Dynamic agent loading now emits warnings (JEP 451), stax.properties file deprecated in favor of jaxp.properties, String Templates (preview), Unnamed Patterns and Variables (preview), Unnamed Classes and Instance Main Methods (preview), Structured Concurrency (preview), Scoped Values (preview)

How Do Virtual Threads Change Concurrent Java Development in JDK 21?

Virtual threads (JEP 444) are now production-ready in Java 21 -- they are lightweight threads managed by the JVM rather than the OS, allowing you to create millions of them without the memory and scheduling overhead of traditional platform threads.

In practice, the biggest win is for thread-per-request server architectures: frameworks like Spring Boot and Quarkus can now use virtual threads as a drop-in replacement for platform threads without rewriting application logic. Code that used to block on I/O (database calls, HTTP requests, file reads) no longer ties up an OS thread during the wait, dramatically improving throughput under load.

// Enable virtual threads in an ExecutorService
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i ->
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return i;
        })
    );
} // virtual threads are cheap -- 10,000 is fine

Watch out for pinned virtual threads: if your code calls synchronized methods that block on I/O, the virtual thread may be pinned to its carrier platform thread, negating the benefit. Use ReentrantLock instead of synchronized blocks in hot I/O paths. The JFR event jdk.VirtualThreadPinned can help you identify these hotspots.

What Do Record Patterns and Pattern Matching for Switch Mean for Everyday Java Code?

Both JEP 440 (Record Patterns) and JEP 441 (Pattern Matching for switch) graduate to final status in Java 21, giving developers a powerful and safe way to deconstruct and branch on data types without cascading instanceof checks or manual casting.

Record patterns let you destructure a record's components directly inside a pattern match. Combined with switch, this enables data-oriented programming that is far more readable than traditional visitor patterns or branching on getClass().

sealed interface Shape permits Circle, Rectangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}

double area(Shape shape) {
    return switch (shape) {
        case Circle(double r) -> Math.PI * r * r;
        case Rectangle(double w, double h) -> w * h;
    };
}

Most teams will find this replaces a large portion of their visitor and strategy boilerplate. The compiler enforces exhaustiveness on sealed hierarchies, so adding a new Shape subtype produces a compile error rather than a silent runtime bug. This is a real upgrade for domain modeling.

Also graduating to final: the switch null handling. You can now explicitly match null inside switch rather than guarding before entry, which removes an entire class of NullPointerException-by-omission bugs in dispatch code.

How Does Generational ZGC Improve Garbage Collection Performance in Java 21?

Generational ZGC (JEP 439) extends the existing low-latency ZGC collector with separate young and old generation heaps, enabling it to collect short-lived objects more frequently and with less CPU overhead than the non-generational variant.

The non-generational ZGC was already impressive for pause times, but it paid a CPU tax because every collection had to consider all live objects. Generational ZGC exploits the generational hypothesis: most objects die young. By collecting the young generation far more often than the old, allocation stalls and GC CPU overhead drop significantly, especially in allocation-heavy workloads.

To enable it, pass both flags:

java -XX:+UseZGC -XX:+ZGenerational -jar myapp.jar

This matters if you are running latency-sensitive services (real-time pricing, gaming backends, trading systems) or any workload that creates a large number of short-lived objects per second. Non-generational ZGC remains available but is expected to be deprecated in a future release, so migrating to the generational variant now is prudent. Note that -XX:+ZGenerational is the opt-in flag for JDK 21; in future releases generational mode is expected to become the default.

What Are the Key Library and API Improvements Shipped With Java 21?

Java 21 delivers several targeted but high-value library additions that address long-standing gaps in everyday API ergonomics.

Sequenced Collections (JEP 431) -- Three new interfaces (SequencedCollection, SequencedSet, SequencedMap) are added to the collections hierarchy, providing uniform getFirst(), getLast(), addFirst(), addLast(), and reversed() methods across List, Deque, LinkedHashSet, and LinkedHashMap. Watch out for source and binary compatibility issues: if your code has a class that extends both a collection interface and defines a conflicting method name, you may hit a compile or link error. Review the JDK 21 Sequenced Collections Incompatibilities document before upgrading.

Math.clamp() -- A new utility method available in four overloads for int, long, float, and double. This eliminates the common Math.min(max, Math.max(min, value)) pattern, which is both verbose and easy to get wrong:

int clamped = Math.clamp(userInput, 0, 255); // clean and readable

HttpClient is now AutoCloseable -- java.net.http.HttpClient implements AutoCloseable, enabling try-with-resources usage and proper resource cleanup. The new shutdown(), shutdownNow(), and awaitTermination(Duration) methods give fine-grained lifecycle control. In practice, avoid creating a new HttpClient per request -- connection pool reuse still matters for performance.

String improvements -- New String.indexOf(int ch, int beginIndex, int endIndex) and String.indexOf(String str, int beginIndex, int endIndex) methods support bounded search ranges and throw on invalid ranges instead of silently returning -1. StringBuilder.repeat(CharSequence, int) and StringBuilder.repeat(int codePoint, int) simplify repeated string construction. String.splitWithDelimiters() returns an array interleaving the split parts and the matched delimiters -- useful for template parsing and text processing.

Key Encapsulation Mechanism API (JEP 452) -- A new standard javax.crypto.KEM API is introduced for hybrid encryption schemes. This matters if you are building post-quantum-safe key exchange, as KEMs are the foundation of algorithms like CRYSTALS-Kyber.

What Breaking Changes and Removals in Java 21 Could Affect Your Upgrade?

Java 21 finalizes the removal of several legacy APIs and JVM options that have been deprecated for years -- most teams will not be impacted, but a few removals deserve attention before you migrate.

  • java.lang.Compiler removed -- This class dated from JDK 1.0 and has done nothing but print a warning since JDK 9. Any direct usage will cause a NoClassDefFoundError at runtime.
  • JAR Index removed -- The META-INF/INDEX.LIST feature (an applet-era optimization) is now ignored entirely. The system property jdk.net.URLClassPath.enableJarIndex no longer has any effect. The jar -i option now emits a warning.
  • java.io.File canonical path cache removed -- The sun.io.useCanonCaches and sun.io.useCanonPrefixCache system properties are gone. This cache was already disabled by default since JDK 12 due to correctness problems with symlinks, so most teams are unaffected.
  • -XX:+EnableWaitForParallelLoad removed -- This legacy HotSpot workaround for old non-parallel-capable class loaders has been dropped. If you were still using this flag, remove it.
  • G1 Hot Card Cache removed -- The JVM options G1ConcRSLogCacheSize and G1ConcRSHotCardLimit are now obsolete. A startup warning will appear if they are present in your JVM flags.
  • RMIIIOPServerImpl removed -- IIOP transport was already gone from JMX Remote in JDK 9; this class now throws UnsupportedOperationException and is fully removed.

On the stewardship front, JEP 451 adds a warning to stderr whenever a JVM TI or Java Agent is loaded dynamically into a running JVM. This is not yet a hard restriction -- it is a preparatory signal that dynamic agent loading will be disallowed by default in a future release. If your observability tooling (APM agents, profilers, coverage tools) loads agents at runtime rather than at startup, you should either add -XX:+EnableDynamicAgentLoading as an explicit opt-in or work with your vendor to migrate to startup-time agent attachment.

In JDK 21.0.11 specifically, TLS server certificates anchored by Chunghwa Telecom root CAs and issued after March 17, 2026 are now distrusted by the JDK's SunJSSE provider. If any of your TLS connections use certificates from this CA chain, verify their issuance dates and renew or re-anchor them as needed.

Frequently Asked Questions about Java 21

Is Java 21 an LTS release and how long is it supported?
Yes, Java 21 is a Long-Term Support release. Oracle provides at least 8 years of Premier Support, making it a solid foundation for production applications that need a stable, long-lived JDK target.

Do Virtual Threads in Java 21 require changes to existing thread pool code?
Most code using ExecutorService can simply switch to Executors.newVirtualThreadPerTaskExecutor() with no other changes. However, if your code relies on synchronized blocks around I/O operations, those blocks can pin virtual threads to carrier threads and reduce throughput, so migrating hot I/O paths to ReentrantLock is recommended.

What flag is needed to enable Generational ZGC in JDK 21?
You need both -XX:+UseZGC and -XX:+ZGenerational on the command line. Generational mode is opt-in in JDK 21 but is expected to become the default in a future release, so enabling it now allows you to test behavior ahead of that change.

Will existing code break due to the Sequenced Collections changes in Java 21?
Most code compiles and runs unchanged, but if you have a class that implements two collection interfaces where both define conflicting default methods with the same name (for example a custom class that was implementing both List and Deque with a conflicting reversed method), you will get a compile error that requires an explicit override to resolve. The Oracle document JDK 21: Sequenced Collections Incompatibilities describes all known conflict scenarios.

How can I suppress the dynamic agent loading warning introduced in JDK 21?
Pass -XX:+EnableDynamicAgentLoading on the JVM command line to explicitly opt in to dynamic agent loading and suppress the warning. Alternatively, configure your agent to attach at JVM startup using the -javaagent or -agentlib flags, which never triggers the warning in any release.

What happened to String Templates, which were previewed in Java 21?
String Templates were introduced as a preview feature in Java 21 via JEP 430. They did not graduate to final status in Java 21 and were subsequently withdrawn from later JDK releases after feedback indicated the design needed further iteration, so you should not depend on them for production use.

Releases In Branch Java SE 21 (LTS)

VersionRelease date
21.0.1121 Apr 2026
(2 months ago)
21.0.1020 Jan 2026
(5 months ago)
21.0.921 Oct 2025
(8 months ago)
21.0.815 Jul 2025
(1 year ago)
21.0.715 Apr 2025
(1 year ago)
21.0.621 Jan 2025
(1 year ago)
21.0.515 Oct 2024
(1 year ago)
21.0.416 Jul 2024
(2 years ago)
21.0.316 Apr 2024
(2 years ago)
21.0.216 Jan 2024
(2 years ago)
21.0.117 Oct 2023
(2 years ago)
2119 Sep 2023
(2 years ago)