Java 21 Features

Published: August 2025

New Features in Java 21

What are Virtual Threads?

Virtual threads are a new lightweight implementation of threads in Java, aimed at simplifying concurrent programming. They allow developers to write code in a synchronous style while benefiting from the scalability of asynchronous programming.

With virtual threads, the Java platform aims to reduce the complexity of writing concurrent code, making it easier for developers to build high-performance applications.

Virtual threads are part of Project Loom, which introduces a new concurrency model to the Java platform.

Traditional threads in Java map directly to OS threads, which consume significant system resources. Virtual Threads are user-mode threads managed by the JVM rather than the operating system. Virtual Threads use far fewer resources compared to platform threads, enabling you to have millions of them.

Benefits of Virtual Threads

How Do Virtual Threads Work?

Virtual threads work by allowing the JVM to manage thread scheduling and execution more efficiently. Instead of relying on the operating system to manage threads, the JVM can optimize the execution of virtual threads based on the application's needs.

This means that virtual threads can be created and destroyed more quickly than traditional threads, and the JVM can make better decisions about how to allocate resources to different threads.

Example Usage

Here's a simple example of using virtual threads in Java:


    Runnable task = () -> {
        System.out.println("Running in a virtual thread");
    };
    Thread.startVirtualThread(task);
        

Example: Using Virtual Threads in Java 21

In Java 21, using virtual threads is straightforward. Here's an example:


    public class VirtualThreadsDemo {
        public static void main(String[] args) throws InterruptedException {
            // Creating a virtual thread
            Thread virtualThread = Thread.ofVirtual().start(() -> {
                System.out.println("Hello from virtual thread " + Thread.currentThread());
            });

            // Wait for the virtual thread to complete
            virtualThread.join();
        }
    }
        

Performance Comparison: Virtual vs Platform Threads

Virtual threads are designed to be more efficient than traditional platform threads. They use less memory and can handle a larger number of concurrent tasks without the overhead associated with OS-level threads.

Let’s compare creating 10,000 threads with traditional platform threads and virtual threads.


    public class ThreadComparison {
        public static void main(String[] args) {
            // Platform Threads
            System.out.println("Platform Threads:");
            long startTime = System.currentTimeMillis();
            for (int i = 0; i < 10000; i++) {
                new Thread(() -> {}).start();
            }
            System.out.println("Completed in " + (System.currentTimeMillis() - startTime) + " ms");

            // Virtual Threads
            System.out.println("\nVirtual Threads:");
            startTime = System.currentTimeMillis();
            for (int i = 0; i < 10000; i++) {
                Thread.ofVirtual().start(() -> {});
            }
            System.out.println("Completed in " + (System.currentTimeMillis() - startTime) + " ms");
        }
    }
        

Sealed classes

Sealed classes are a new feature in Java 21 that allow developers to control which classes can extend or implement them. This is useful for creating a more predictable and maintainable class hierarchy.

Benefits of Sealed Classes

Why Use Sealed Classes?

Example of Sealed Classes


    public sealed class Shape permits Circle, Rectangle {
    }

    public final class Circle extends Shape {
    }

    public final class Rectangle extends Shape {
    }
        

Example: Using Sealed Classes

Define a Sealed Class:
    // Define a Sealed Class:
    public sealed class Shape permits Circle, Rectangle, Triangle {
        public abstract double area(); // Abstract method for area calculation
    }

    // Circle is a permitted class extending Shape
    public final class Circle extends Shape {
        private final double radius;

        public Circle(double radius) {
            this.radius = radius;
        }

        @Override
        public double area() {
            return Math.PI * radius * radius;
        }
    }

    // Rectangle is another permitted class
    public final class Rectangle extends Shape {
        private final double length, width;

        public Rectangle(double length, double width) {
            this.length = length;
            this.width = width;
        }

        @Override
        public double area() {
            return length * width;
        }
    }

    // Triangle is also permitted
    public non-sealed class Triangle extends Shape {
        private final double base, height;

        public Triangle(double base, double height) {
            this.base = base;
            this.height = height;
        }

        @Override
        public double area() {
            return 0.5 * base * height;
        }
    }