# java21新特性

# Virtual Threads(虚拟线程)

虚拟线程是 JVM 层面实现的轻量级线程,核心目标是以极低的开销解决传统线程(OS 线程)的资源瓶颈,让 Java 能高效处理海量并发任务(比如百万级 IO 密集型请求)。

# 为什么需要虚拟线程?

传统的 Java 线程:

  1. 资源消耗高:每个 OS 线程占用内存大,服务器能创建的线程数上限仅几千到几万;
  2. 阻塞代价大:当线程因 IO 阻塞时,OS 线程会被挂起,浪费系统资源;
  3. 并发瓶颈:高并发场景下,线程数不足会导致请求排队,性能无法提升。

虚拟线程则是 JVM 管理的 轻量级线程,彻底解决了这些问题:

  • 单个 JVM 可创建数百万虚拟线程,内存占用小;
  • 虚拟线程阻塞时,JVM 会自动将其与 OS 线程解绑,OS 线程可处理其他虚拟线程,资源利用率接近 100%;(核心
  • 编程模型与传统线程一致,无需学习新的异步 API(如 CompletableFuture)。

# 虚拟线程的核心用法

public class VirtualThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        // 方式1:直接创建并启动(推荐简单场景)
        Thread virtualThread1 = Thread.ofVirtual().start(() -> {
            System.out.println("虚拟线程1执行:" + Thread.currentThread());
            // 模拟IO阻塞(虚拟线程阻塞时会自动让出OS线程)
            try { Thread.sleep(1000); } catch (InterruptedException e) {}
        });

        // 方式2:创建未启动的虚拟线程
        Thread virtualThread2 = Thread.ofVirtual().unstarted(() -> {
            System.out.println("虚拟线程2执行:" + Thread.currentThread());
        });
        virtualThread2.start();

        // 方式3:通过线程池创建(推荐高并发场景)
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            // 提交100万个任务(虚拟线程轻松支撑)
            for (int i = 0; i < 100_0000; i++) {
                int finalI = i;
                executor.submit(() -> {
                    Thread.sleep(1000); // 模拟IO阻塞
                    return finalI;
                });
            }
        } // 线程池自动关闭
        // 等待所有任务执行完毕,防止因主线程退出而守护线程提前结束
        virtualThread1.join();
        virtualThread2.join();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# Switch模式匹配

Switch 模式匹配(Pattern Matching for switch) 特性,它是对 Java 14 开关表达式、Java 16 instanceof 模式匹配的全面升级 —— 让 switch 能基于类型、值、解构多维度匹配,彻底简化复杂的分支判断逻辑。

1.类型模式匹配(替代 instanceof + switch)

// 传统写法(instanceof + 多个if-else)
public static String getTypeOld(Object obj) {
    if (obj instanceof String s) {
        return "字符串:" + s.length();
    } else if (obj instanceof Integer i) {
        return "整数:" + (i * 2);
    } else if (obj instanceof Double d) {
        return "浮点数:" + d;
    } else {
        return "未知类型";
    }
}

// Java 21 Switch 类型模式
public static String getTypeNew(Object obj) {
    return switch (obj) {
        case String s -> "字符串:" + s.length(); // 类型匹配 + 变量声明
        case Integer i -> "整数:" + (i * 2);
        case Double d -> "浮点数:" + d;
        case null -> "空值"; // 显式匹配null,避免NPE
        default -> "未知类型";
    };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

2.在 case 中添加条件筛选,实现类型匹配 + 业务规则的双重判断

public static String getValidValue(Object obj) {
        return switch (obj) {
            // 类型匹配 + 条件筛选(卫语句)
            case String s when s.length() > 5 -> "有效字符串:" + s;
                case String s -> "短字符串:" + s;
            case Integer i when i > 0 -> "正整数:" + i;
                case Integer i -> "非正整数:" + i;
                default -> "无效值";
        };
    }
1
2
3
4
5
6
7
8
9
10

# Records增强

在前面我们学习了record去代替一些传统的数据类

// 定义一个 Record
public record User(String id, String name, int age) {}

// 使用
User user = new User("1", "张三", 25);
System.out.println(user.name()); // 直接访问字段(无get前缀)
1
2
3
4
5
6

Java 21 最大的升级是让 Records 与 Switch 模式匹配无缝结合,支持在 switch 中直接解构 Record 字段,无需手动调用访问器,代码更简洁。

// 定义形状相关的 Record
public record Point(int x, int y) {}
public record Circle(Point center, double radius) {}
public record Rectangle(Point topLeft, Point bottomRight) {}

// 用 Switch 解构 Record
public static String describeShape(Object shape) {
    return switch (shape) {
        // 直接解构 Point 的 x、y 字段
        case Point(int x, int y) -> "点:(" + x + "," + y + ")";
        // 嵌套解构 Circle 的圆心和半径
        case Circle(Point(int cx, int cy), double r) -> 
            "圆:圆心(" + cx + "," + cy + "),半径" + r;
        // 简化写法:用变量名接收解构结果
        case Rectangle(Point tl, Point br) -> 
            "矩形:左上角" + tl + ",右下角" + br;
        default -> "未知图形";
    };
}

// 调用示例
public static void main(String[] args) {
    Circle circle = new Circle(new Point(10, 20), 5.0);
    System.out.println(describeShape(circle));
    // 输出:圆:圆心(10,20),半径5.0
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 有序集合

Java 21 的有序集合为我们提供了更直观的方式来操作集合的头尾元素,说白了就是补了几个方法

public static void main(String[] args) {

        List<String> tasks = new ArrayList<>();
        tasks.addFirst("任务1");   // 添加到开头
        tasks.addLast("任务2");    // 添加到结尾

        String firstStr = tasks.getFirst();  // 获取第一个
        String lastStr = tasks.getLast();    // 获取最后一个

        String removedFirst = tasks.removeFirst();  // 删除并返回第一个
        String removedLast = tasks.removeLast();    // 删除并返回最后一个

        List<String> reversed = tasks.reversed();   // 反转列表
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

原理也很简单就是继承了有序集合

本地图片

# 【了解】分代 ZGC

Java 21 中的分代 ZGC 可以说是垃圾收集器领域的一个重大突破。ZGC 从 Java 11 开始就以其超低延迟而闻名,但是它并没有采用分代的设计思路。

在这之前,ZGC 对所有对象一视同仁,无论是刚创建的新对象还是存活了很久的老对象,都使用同样的收集策略。这虽然保证了一致的低延迟,但在内存分配密集的应用中,效率并不是最优的。

简而言之:把对象分两种(生命周期短的和生命周期长的),一个放左边一个放右边,当短期对象活的久了变为长期对象到右边,左右两边采取不同的回收策略,减少内存浪费

本地图片

最近更新: 9/19/2026, 1:27:08 PM
编程NOTE   |