Java in 2026: Virtual Threads, AOT Cache, Markdown Docs, and More

I started my careers in Java 8. Since then Java 11,17,21,25 and now Java 26. Even though I have migrated many microservice from Java 11 to Java 21 didn’t use any modern features because our focus was to eliminate vulnerabilities.

These new Java features are really game changing. The new JDK comes with lot of performance improvements and new ways of writing and operating Java apps. Lets see some of the cool things that I found as interesting.

Virtual Threads

Before Java 21 we had only platform threads. Which is borrowed from OS. These threads are inefficient and limited. Also resource heavy to create and discard.

Project Loom was created to work on finding a way to improve Java for concurrency. Where Go and Rust dominates. Project Loom came up with virtual threads and the result is really impressive.

Take a look at a simple bench mark of Old Platform Threads and new Virtual Threads.

100k Tasks: Old Platform Threads
------------------------------------
Total execution time : 5148 ms
Slowest task : Thread-740
Slowest task time : 61 ms
------------------------------------
100k Tasks: New Virtual Threads
------------------------------------
Total execution time : 436 ms
Slowest thread : Thread-44695
Slowest thread time : 82 ms
------------------------------------

This is huge difference.

And to use this in your spring boot application all you need to do is add a config in application properties.

spring.threads.virtual.enabled=true

Along with Structured Concurrency and Scoped values. Working with Concurrency in Java has never been this good.

GraalVM Native Image

Traditionally we build our spring boot service as your-service-name.jar which needs a JVM to run this service. Each time we start the service it takes 10s to 50s depending upon project size. In cloud env when we have sudden spike in traffic we need to scale immediately.

Netflix has same issue. To their scale of traffic they can’t wait for 50s to scale. What they do is keep few replicas ready all the time. That’s 1000s of replicas sitting idle costing millions of dollar.

GraalVM Native Image fix’s this issues. You can convert your spring boot service into native image. Native images can start in milliseconds and be ready for accepting traffic.

Advantages

  • Startup time - 10x faster
  • Memory usage - 50% lower

Disadvantages

  • Peak throughput - Slightly lower

Because No JIT. We don’t get the runtime optimizations. So bad of scale of Netflix because they need throughput. But still this is good for startup companies. Which can save lot of cost in memory and CPU. Unless you don’t have high traffic like Netflix.

AOT Cache

If you can’t lose JIT but still you want to improve startup time by 15 to 30% faster AOT Cache can help.

The AOT Cache (Ahead-of-Time Cache) stores pre-processed class metadata, loaded classes, and linking information from a training run, so the JVM can skip repeating that work on subsequent startups. This significantly reduces JVM startup time and time-to-peak-performance, especially useful for short-lived processes like CLI tools or serverless functions.

Steps to use AOT

After building spring boot app. Use below commands to generate .aot

java -Djarmode=tools -jar demo-0.0.1-SNAPSHOT.jar extract --destination application
cd application
java -XX:AOTCacheOutput=app.aot -Dspring.context.exit=onRefresh -jar demo-0.0.1-SNAPSHOT.jar

This will create app.aot

Then run the app with app.aot cache

java -XX:AOTCache=app.aot -jar demo-0.0.1-SNAPSHOT.jar

Result

Same application with and without AOT Cache:

Started DemoApplication in 1.22 seconds (process running for 1.475)

Started DemoApplication in 3.102 seconds (process running for 3.4)

Check out how Netflix has implemented AOT.

Markdown in Javadoc

Markdown in Javadoc lets you write doc comments using /// and standard Markdown syntax (like `, -, ##) instead of HTML tags inside /** */ blocks. It produces the same generated documentation but is much easier to read and write directly in the source code.

Example - Traditional Javadoc

1/**
2 * A simple utility class for printing greetings.
3 * <p>
4 * This class demonstrates the traditional Javadoc style
5 * using HTML tags and {@code @} block tags. It provides:
6 * <ul>
7 * <li>a method to print a personalized or generic greeting</li>
8 * <li>a {@code main} method to demonstrate usage</li>
9 * </ul>
10 *
11 * <p>Example usage:
12 * <pre>{@code
13 * HelloWorldOld.sayHello("Traditional Javadoc");
14 * // prints: Hello, Traditional Javadoc!
15 * }</pre>
16 *
17 * @author udhayakumarth
18 * @since 1.0
19 * @see java.lang.System#out
20 */
21public class TraditionalJavadoc {
22
23 public static void sayHello(String name) {
24 if (name == null || name.isBlank()) {
25 System.out.println("Hello, World!");
26 } else {
27 System.out.println("Hello, " + name + "!");
28 }
29 }
30
31 public static void main(String[] args) {
32 sayHello(null); // Hello, World!
33 sayHello("Traditional Javadoc"); // Hello, Traditional Javadoc!
34 }
35}

Example - Markdown Javadoc

1/// A simple utility class for printing greetings.
2///
3/// This class demonstrates the new **Markdown-style** Javadoc
4/// introduced in JEP 467. It provides:
5///
6/// - a method to print a personalized or generic greeting
7/// - a `main` method to demonstrate usage
8///
9/// ## Example
10///
11/// ```
12/// HelloWorldNew.sayHello("Markdown");
13/// // prints: Hello, Markdown!
14/// ```
15///
16/// @author udhayakumarth
17/// @since 1.0
18/// @see java.lang.System#out
19public class MarkdownJavadocs {
20
21 public static void sayHello(String name) {
22 if (name == null || name.isBlank()) {
23 System.out.println("Hello, World!");
24 } else {
25 System.out.println("Hello, " + name + "!");
26 }
27 }
28
29 public static void main(String[] args) {
30 sayHello(null); // Hello, World!
31 sayHello("Markdown"); // Hello, Markdown!
32 }
33}