一、Java19新特性
2022年9月21日 Java19 正式发布,带来了一个 Java 开发者垂涎已久的新特性—— 虚拟线程。在 Java 有这个新特性之前,Go语言的协程风靡已久,在并发编程领域可以说是叱咤风云。随着国内 Go 语言的快速发展与推广,协程好像成为了一个世界上最好语言的必备特性之一。
JKD19发布了7个新特性:大部分是预览版,但是预览版也是稳定的功能,只是说以后可能会移除或者迁移
- 405:Record Patterns (Preview) 记录模式
- 422:Linux/RISC-V Port Linux/RISC-V 移植
- 424:Foreign Function & Memory API (Preview) 外部函数和内存 API
- 425:Virtual Threads (Preview) 虚拟线程
- 426:Vector API (Fourth Incubator) 向量 API
- 427:Pattern Matching for switch (Third Preview) Switch 模式匹配
- 428:Structured Concurrency (Incubator) 结构化并发
EP 405 Record Patterns (Preview)
记录模式(预览版)
Enhance the Java programming language with record patterns to deconstruct record values. Record patterns and type patterns can be nested to enable a powerful, declarative, and composable form of data navigation and processing. This is a preview language feature.
使用记录模式增强 Java 编程语言以解构记录值,可以嵌套记录模式和类型模式,实现强大的、声明性的和可组合的数据导航和处理形式。
JEP 424 Foreign Function & Memory API (Preview)
外部函数和内存API(预览版)
Introduce an API by which Java programs can interoperate with code and data outside of the Java runtime. By efficiently invoking foreign functions (i.e., code outside the JVM), and by safely accessing foreign memory (i.e., memory not managed by the JVM), the API enables Java programs to call native libraries and process native data without the brittleness and danger of JNI. This is a preview API.
引入一个API,Java 程序可以通过该 API 与 Java 运行时之外的代码和数据进行互操作。通过该 API 可有效地调用外部函数( JVM 之外的代码)和安全地访问外部内存(不受 JVM 管理的内存),使得 Java 程序能够调用本机库并处理本机数据,而不会出现 JNI 的脆弱性和危险。
JEP 425 Virtual Threads (Preview)
虚拟线程(预览版)
Introduce virtual threads to the Java Platform. Virtual threads are lightweight threads that dramatically reduce the effort of writing, maintaining, and observing high-throughput concurrent applications. This is a preview API.
将虚拟线程引入 Java 平台。虚拟线程是轻量级线程,可显著地减少编写、维护和观察高吞吐量并发应用程序的工作量。
JEP 426 Vector API (Fourth Incubator)
向量API(第四次孵化)
Introduce an API to express vector computations that reliably compile at runtime to optimal vector instructions on supported CPU architectures, thus achieving performance superior to equivalent scalar computations.
引入一个 API 来表达在运行时能够可靠编译的向量计算,在支持的 CPU 架构上优化向量指令,从而实现优于标量计算的性能。
JEP 427 Pattern Matching for switch (Third Preview)
switch模式匹配(第三次预览版)
Enhance the Java programming language with pattern matching for switch expressions and statements. Extending pattern matching to switch allows an expression to be tested against a number of patterns, each with a specific action, so that complex data-oriented queries can be expressed concisely and safely. This is a preview language feature.
用 switch 表达式和语句的模式匹配,以及对模式语言的扩展来增强 Java 编程语言。将模式匹配扩展到 switch 中,允许针对一些模式测试表达式,这样就可以简明而安全地表达复杂的面向数据的查询。
JEP 428 Structured Concurrency (Incubator)
结构化兵法(孵化阶段)
Simplify multithreaded programming by introducing an API for structured concurrency. Structured concurrency treats multiple tasks running in different threads as a single unit of work, thereby streamlining error handling and cancellation, improving reliability, and enhancing observability. This is an incubating API.
引入用于结构化并发的 API 来简化多线程编程,结构化并发将不同线程中运行的多个任务视为单个工作单元,从而简化错误处理、提高可靠性并增强可观察性。
二、虚拟线程
Java线程模型
Java 线程 与 虚拟线程
我们常用的Java线程和系统内核线程是一一对应的,系统内核的线程调度程序负责调度 Java 线程。为了增加应用程序的性能,我们会增加越来越多的 Java 线程,显然系统调度 Java 线程时,会占据不少资源去处理线程上下文切换。
我们一直使用上图的Java线程模型来解决Java并发编程问题,为了增加系统的吞吐量,我们要不断增加线程的数量,但是机器的线程数量是昂贵的,线程数量也是有限的,就算使用各种手段进行优化,切换上下文仍然带来很大的开销,使我们的系统仍然不能充分使用硬件性能。
为了充分利用硬件性能,Java19引入了虚拟线程。在 Java19 中,之前我们常用的线程叫做平台线程(platform thread),与系统内核线程仍然是一一对应的。其中大量(M)的虚拟线程在较小数量(N)的平台线程(与操作系统线程一一对应)上运行(M:N调度)。多个虚拟线程会被 JVM 调度到某一个平台线程上执行,一个平台线程同时只会执行一个虚拟线程。
创建 Java 虚拟线程
//输出线程ID 包括虚拟线程和系统线程 Thread.getId() 从jdk19废弃
Runnable runnable = () -> System.out.println(Thread.currentThread().threadId());
//创建虚拟线程
Thread thread = Thread.ofVirtual().name("testVT").unstarted(runnable);
testVT.start();
//创建虚平台线程
Thread testPT = Thread.ofPlatform().name("testPT").unstarted(runnable);
testPT.start();
使用Thread.startVirtualThread(Runnable)快速创建虚拟线程并启动:
//输出线程ID 包括虚拟线程和系统线程
Runnable runnable = () -> System.out.println(Thread.currentThread().threadId());
Thread thread = Thread.startVirtualThread(runnable);
Thread.isVirtual()判断线程是否为虚拟线程:
Runnable runnable = () -> System.out.println(Thread.sleep(10));
Thread thread = Thread.startVirtualThread(runnable);
//等待虚拟线程结束
thread.join();
Executors.newVirtualThreadPerTaskExecutor()创建一个 ExecutorService,该 ExecutorService 为每个任务创建一个新的虚拟线程:
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> System.out.println("hello"));
}
注意:因为虚拟线程在 Java19 中是预览特性,所以本文出现的代码需按以下方式运行:
-
使用
javac --release 19 --enable-preview Main.java编译程序,并使用java --enable-preview Main运行; -
或者使用
java --source 19 --enable-preview Main.java运行程序;
原理
虚拟线程不是更快的线程,它们运行代码的速度与平台线程相比并无优势。虚拟线程的存在是为了提供更高的吞吐量,而不是速度(更低的延迟)。
什么时候适合用虚拟线程?
如果你的应用程序符合下面两点特征,使用虚拟线程可以显著提高程序吞吐量:
-
程序并发任务数量很高。
-
IO密集型、工作负载不受 CPU 约束。
虚拟线程有助于提高服务端应用程序的吞吐量,因为此类应用程序有大量并发,而且这些任务通常会有大量的 IO 等待。
三、Java8以后的jdk各个版本都有什么新特性?需要升级吗?
强烈推荐升级JDK17
目前大部分国内公司都还在使用JDK8,但其实新版本的JDK无论是速度还是稳定性都已经有很大的进步,尤其是JDK17,包括ZGC、内存管理等新特性的发布,在性能和垃圾回收的效率方面有了长足的提升,包括将要发布的Spring Boot 3.0 也是要求JDK的最低版本为JDK17,而且JDK17也是长期支持的版本,所以推荐所有公司升级到JDK17。
Spring Boot也应升级到最新的2.7版本,到时候升级到Spring Boot 3.0也会容易迁移。Spring Boot 3.0 是不兼容JDK17以前的版本的,所以是必须要升级的,这会倒逼一部分公司升级到JDK17,光升级JDK很多公司都没有动力,但是要升级Spring就不一样了,Spring Boot 3.0应该会有极大的改变,吸引公司升级。Spring Boot 3.0 目前已经发布多个版本,详情查看:github.com/spring-proj…
JDK9
模块系统、REPL (JShell)、HTTP 2 客户端等、多版本兼容 JAR 包等新特性。详情点击
JDK10
局部变量 var、基于 Java 的 JIT 编译器等新特性。详情点击
JDK11(LTS)
引入ZGC、字符串API加强、Stream增加API、HttpClient支持HTTP2等新功能。详情点击
JDK12
Shenandoah 低暂停时间垃圾收集器、Microbenchmark Suite、 Switch 表达式(预览版)、安全库等新功能。详情点击
JDK13
Uncommit Unused Memory (归还空闲内存)、重新实现Socket API等新特性。详情点击
JDK14
instanceof 的模式匹配、移除CMS(Concurrent Mark Sweep)垃圾收集器等新特性。详情点击
JDK15
密封类、文本块、ZGC优化等新特性。详情点击
JDK16
内存管理方面的提升、Unix-Domain Socket Channel、封装内部JDK包等新特性。详情点击
JDK17(LTS)
密封类转正、macOS/AArch64 平台支持(M1)、 提供了数以千计的性能、稳定性和安全更新,以及 14 个 JEP(JDK 增强建议)。详情点击
JDK18
指定 UTF-8 作为标准 Java API、引入一个简单的 Web 服务器、用方法句柄重新实现核心反射等新特性。详情点击