Skip to content

Java 20

Neelu edited this page Jul 26, 2026 · 1 revision

☕ Java 20: Scoped Values & Concurrency Previews Continue

Release Date: March 21, 2023 | Type: Standard (non-LTS) | Status: ⚠️ End of Life


📋 Table of Contents

  1. Overview
  2. Core Features
  3. Best Practices

🎯 Overview

Java 20 is a "consolidation" release — no brand-new headline feature, but it refines Record Patterns, re-previews Virtual Threads and Structured Concurrency with API improvements, and introduces Scoped Values as a modern, virtual-thread-friendly alternative to ThreadLocal.

flowchart LR
    A[Java 19: Virtual Threads Preview] --> B[Java 20: Virtual Threads 2nd Preview]
    C[Java 19: Structured Concurrency Incubator] --> D[Java 20: 2nd Incubator]
    E[Java 19: Record Patterns Preview] --> F[Java 20: 2nd Preview]
    G[NEW] --> H[Scoped Values Incubator]
Loading

🚀 Core Features

1️⃣ Scoped Values (Incubator)

What: An immutable alternative to ThreadLocal, designed to work efficiently with millions of virtual threads. Data is shared for the duration of a call, then automatically un-shared — no leaks, no mutation surprises.

// ThreadLocal — mutable, can leak across thread-pool reuse, expensive with virtual threads
private static final ThreadLocal<String> CURRENT_USER = new ThreadLocal<>();

CURRENT_USER.set("alice");
try {
    process();
} finally {
    CURRENT_USER.remove();  // ⚠️ easy to forget — causes leaks
}

// Scoped Values — immutable, automatically bounded, virtual-thread-friendly
private static final ScopedValue<String> CURRENT_USER = ScopedValue.newInstance();

ScopedValue.where(CURRENT_USER, "alice").run(() -> {
    process(); // CURRENT_USER.get() == "alice" ONLY within this block
});
// Automatically un-bound here — no cleanup code needed, no leak possible
flowchart TD
    A["ThreadLocal.set()"] --> B["Value persists until\nexplicitly removed"]
    B --> C{"Thread reused\nfrom pool?"}
    C -->|Forgot remove| D["❌ Leaked value\nseen by next task"]

    E["ScopedValue.where().run()"] --> F["Value bound ONLY\nfor the lambda's duration"]
    F --> G["Automatically unbound\nwhen lambda returns"]
    G --> H["✅ No leak possible,\nno manual cleanup"]
Loading

Why it matters for virtual threads: ThreadLocal values get copied/inherited in ways that don't scale well to millions of virtual threads. ScopedValue was purpose-built to be cheap and safe at that scale.


2️⃣ Record Patterns (2nd Preview)

Refinements to the Java 19 preview — adds support for record patterns in switch (not just instanceof):

record Point(int x, int y) {}
record Line(Point start, Point end) {}

static String describe(Object shape) {
    return switch (shape) {
        case Line(Point(var x1, var y1), Point(var x2, var y2))
            when x1 == x2 -> "Vertical line";
        case Line(Point s, Point e) -> "Line from " + s + " to " + e;
        case Point(var x, var y) -> "Point at (" + x + ", " + y + ")";
        default -> "Unknown shape";
    };
}

3️⃣ Virtual Threads (2nd Preview)

API refinements based on Java 19 feedback — no major conceptual changes. See the Java 19 guide for the core concept, standardized fully in Java 21.


4️⃣ Structured Concurrency (2nd Incubator)

// API stabilizing toward what ships in Java 21+
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    var user = scope.fork(() -> fetchUser(id));
    var prefs = scope.fork(() -> fetchPreferences(id));
    scope.join().throwIfFailed();
    return new Profile(user.resultNow(), prefs.resultNow());
}

5️⃣ Foreign Function & Memory API (2nd Preview)

// Continued refinement toward Java 22 standardization
try (Arena arena = Arena.ofConfined()) {
    MemorySegment segment = arena.allocate(100);
    segment.set(ValueLayout.JAVA_INT, 0, 42);
    int value = segment.get(ValueLayout.JAVA_INT, 0);
}

💡 Best Practices

✅ If you're already using ThreadLocal for request-scoped data (user context, trace IDs), start planning a migration path to ScopedValue once it standardizes
✅ Keep experimenting with virtual threads and structured concurrency — Java 20 is the last "preview lap" before Java 21 LTS standardizes both
❌ Don't adopt Java 20 in production for its own sake — it's a non-LTS release with a short support window; wait for Java 21 unless you need a specific preview feature today


Clone this wiki locally