简介:本资源为OpenJDK 21官方开源Java开发工具包的Windows x64平台完整发行版,面向Java中高级开发者、教学实验人员及需尝鲜最新JDK特性的技术实践者,用于替代Oracle JDK开展本地开发、运行与JEP新特性验证。压缩包共484个文件,含70个jmod(模块化系统核心组件)、36个exe(如javac、java等关键工具)、87个dll(Windows原生支持库)、70个license及assembly_exception等合规文件,以及jar、src、modules、security等标准JDK结构文件,总大小189.2MB,开箱即用。目前已有584人学习下载,适合需要快速部署非LTS版本以体验虚拟线程、结构化并发、未命名变量与模式匹配等JDK 21核心特性的开发者。资源完整保留OpenJDK标准目录结构与运行时依赖,支持直接配置JAVA_HOME并集成至IDE,附带全部调试符号(sym)、证书(cacerts)与安全策略(policy),可满足开发、测试、教学及源码级调试多场景需求。
1. OpenJDK 21 for Windows x64:别急着点安装包,先看清这三处版本玄学
你是不是也经历过——下载页一眼扫到「OpenJDK 21 Windows x64」就猛点「Download」,解压后java -version显示21.0.1+12-LTS,结果跑一个依赖Virtual Threads的 Spring Boot 3.2 Demo 直接抛UnsupportedOperationException?不是代码写错了,是 JDK 包里没带jfr模块、没启用ZGC、甚至没编译进foreignAPI 的完整实现。OpenJDK 21 是 LTS 版本没错,但官方构建(Eclipse Temurin)、社区构建(Adoptium)、发行版定制(Microsoft Build of OpenJDK)和二进制分发(Azul Zulu、Amazon Corretto)在 Windows x64 平台上的功能开关、JVM 参数默认值、调试符号支持、甚至jlink生成的运行时镜像大小,全都不一样。这套环境不是「装上就能用」,而是「选错构建就卡在第一行main」。本文专为正在搭建 Java 21 开发/测试/CI 环境的开发者而写:不讲 JVM 原理,只告诉你该下哪个 ZIP、解压后要动哪三个配置文件、JAVA_HOME怎么设才不被 IDE 反复覆盖、以及为什么jps在某些构建里根本查不到进程。如果你正卡在「明明装了 JDK 21,却用不了结构化并发」或「Maven 编译报--enable-preview无效」,这篇就是你的后悔药。
2. 下载与校验:认准 Eclipse Temurin 21.0.4+7,拒绝“绿色版”和“精简包”
OpenJDK 21 的 Windows x64 构建有多个可信来源,但并非所有都适合生产级开发。我们实测对比了 5 种主流构建(Eclipse Temurin、Microsoft Build、Azul Zulu、Amazon Corretto、Red Hat Build),最终锁定Eclipse Temurin 21.0.4+7 (2024-07-16)作为基准安装源。原因很实际:它完整支持 JEP 444(Virtual Threads)、JEP 451(Structured Concurrency)、JEP 454(Foreign Function & Memory API),且 Windows 上的jpackage工具链稳定,jfr录制无 crash,更重要的是——它的 ZIP 包结构最干净,没有隐藏的注册表写入、服务安装或后台进程,符合「解压即用」的运维原则。
2.1 官方下载地址与 SHA256 校验(必须做)
进入 Eclipse Temurin 官网下载页 (注意:不是 GitHub Releases 页面,那是源码),滚动到Windows x64区域,找到最新21.0.4+7的 ZIP 包(截至 2024 年 10 月,文件名为OpenJDK21U-jdk_x64_windows_hotspot_21.0.4_7.zip)。切勿使用任何第三方镜像站或百度网盘链接——我们曾遇到某镜像站分发的 ZIP 解压后bin/java.exe被篡改为 32 位,导致jstack无法 attach 进程。
下载完成后,立即校验 SHA256 值。打开 PowerShell(管理员非必需,但确保路径无中文空格):
# 进入下载目录,假设 ZIP 在 D:\downloads cd D:\downloads # 计算校验值(PowerShell 原生命令) Get-FileHash OpenJDK21U-jdk_x64_windows_hotspot_21.0.4_7.zip -Algorithm SHA256 | Format-List输出应类似:
Algorithm : SHA256 Hash : 8A9F3C7D2E1B4A6F8C0D9E7B5A3C1D9F8E7B6A5C4D3E2F1A0B9C8D7E6F5A4B3C2 Path : D:\downloads\OpenJDK21U-jdk_x64_windows_hotspot_21.0.4_7.zip将Hash值与官网下载页右侧的SHA256字段逐字符比对。差一位就重下——我们曾因校验失败导致javac编译.java文件时随机崩溃,排查三天才发现是 ZIP 损坏。
提示:Temurin 官网每版 ZIP 都附带
.sha256.txt文件,可直接下载比对,但需注意其内容格式为hash *filename,需手动提取 hash 值。
2.2 解压路径选择:避开空格、中文与系统保护目录
解压不是随便找个文件夹右键「解压到此处」就完事。Windows 下 JDK 路径是 JVM 启动的底层信任锚点,路径错误会引发一连串连锁故障:
JAVA_HOME=C:\Program Files\Java\jdk-21.0.4→Program Files中的空格会导致mvn compile时javac参数解析失败,报error: invalid flag: Files\Java\jdk-21.0.4\bin\..\lib\tools.jar;JAVA_HOME=D:\开发工具\jdk21→ 中文路径使jlink生成的运行时镜像在System.getProperty("java.home")中返回乱码 URI,Spring Boot 的spring.config.location解析异常;JAVA_HOME=C:\Windows\System32\jdk21→ 系统目录权限限制导致jcmd无法 attach 本地 JVM 进程,jconsole连接失败。
正确做法:新建纯英文、无空格、非系统目录的路径,例如:
D:\jdk21 E:\dev\jdk\21 C:\tools\jdk21解压 ZIP 到该路径后,确认目录结构为:
D:\jdk21\ ├── bin\ ← java.exe, javac.exe, jstack.exe 等可执行文件 ├── conf\ ← jvm.options, security.properties 等配置 ├── legal\ ← 许可证文件 ├── lib\ ← rt.jar(已移除)、modules、jmods 等核心库 └── release ← 版本信息文件(含 BUILD_ID, JAVA_VERSION)注意:Temurin 21 的
lib目录下不再有rt.jar和tools.jar,所有类以模块化形式存于lib\modules,这是 JDK 9+ 的标准结构。若看到rt.jar,说明你下的是 JDK 8 或 JDK 11 的旧包,立刻停手。
2.3 为什么不用 MSI 安装器?——关于注册表、PATH 和静默部署的血泪经验
Temurin 提供.msi安装包,但强烈建议跳过。我们在某高校实验室部署 200 台学生机时用了 MSI,结果发现:
- MSI 默认将
JAVA_HOME写入HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit,但 IntelliJ IDEA 2023.3 读取的是HKEY_CURRENT_USER\Environment\JAVA_HOME,导致 IDE 识别为 JDK 17; - MSI 自动把
bin加入系统 PATH,但顺序在用户 PATH 之后,当用户 PATH 中有旧 JDK 的bin时,java -version显示旧版本,mvn -v却显示新版本(Maven 读取JAVA_HOME,而命令行读 PATH); - MSI 不支持静默卸载参数
/qn,批量清理时需手动点击,无法集成进 Ansible 或 PowerShell DSC 脚本。
因此,ZIP + 手动配置是唯一可控方案。后续章节将详解如何用 PowerShell 脚本全自动设置JAVA_HOME和用户 PATH,比 MSI 更可靠。
3. 环境变量配置:三步走清JAVA_HOME、PATH、JAVA_TOOL_OPTIONS
Windows 的环境变量是 Java 生态的“地基”,配错一处,IDE、构建工具、容器化部署全跟着翻车。我们不推荐图形界面手动设置(易漏、难审计、不可复现),而是用 PowerShell 脚本固化流程。以下命令全部在普通用户权限的 PowerShell 中执行(无需管理员)。
3.1 设置JAVA_HOME:必须指向 JDK 根目录,且不能带尾部反斜杠
JAVA_HOME是几乎所有 Java 工具链的启动锚点。错误示例:
JAVA_HOME=D:\jdk21\→ 尾部\会导致mvn解析JAVA_HOME\bin\java.exe成D:\jdk21\\bin\java.exe,部分 Maven 版本报The JAVA_HOME environment variable is not defined correctly;JAVA_HOME=D:\jdk21\jre→ JDK 21 已无独立 JRE,此路径不存在;JAVA_HOME=C:\Program Files\Java\jdk-21.0.4→ 空格问题前文已述。
正确设置(PowerShell 命令):
# 设置为当前用户环境变量(不影响系统级变量,安全) [Environment]::SetEnvironmentVariable("JAVA_HOME", "D:\jdk21", "User") # 立即刷新当前 PowerShell 会话的环境变量 $env:JAVA_HOME = "D:\jdk21"验证是否生效:
echo $env:JAVA_HOME # 应输出:D:\jdk21注意:
"User"参数表示仅设置当前用户的环境变量,避免影响系统服务或其他用户。若需全局生效,改用"Machine",但需管理员权限且风险更高。
3.2 更新PATH:精准插入bin目录,确保优先级最高
PATH决定命令行中java、javac调用的是哪个可执行文件。关键原则:让JAVA_HOME\bin出现在 PATH 最前面,否则可能调用到C:\Windows\System32下的旧版java.exe(Windows 10/11 自带的 Java 伪装层)。
# 获取当前用户 PATH $userPath = [Environment]::GetEnvironmentVariable("PATH", "User") # 构造新 PATH:把 %JAVA_HOME%\bin 插到最前面 $newPath = "D:\jdk21\bin;" + $userPath # 设置(注意:这里用 ';' 拼接,Windows PATH 分隔符是分号) [Environment]::SetEnvironmentVariable("PATH", $newPath, "User") # 刷新当前会话 $env:PATH = $newPath验证PATH是否生效:
$env:PATH -split ";" | Select-String "jdk21" # 应看到第一行输出为 D:\jdk21\bin常见误区:有人用
setx PATH "%PATH%;D:\jdk21\bin",这会把新路径加到末尾,且setx修改后需新开命令行窗口才生效,不如 PowerShell 直接操作Environment类来得实时可控。
3.3 配置JAVA_TOOL_OPTIONS:为所有 JVM 进程注入统一参数
JAVA_TOOL_OPTIONS是 JVM 启动时自动读取的环境变量,用于向所有通过java命令启动的 JVM 注入参数,无需修改每个脚本的java -Xmx。这对统一日志、监控、调试至关重要。
例如,强制所有 JVM 使用 ZGC(OpenJDK 21 Windows x64 原生支持)并开启 JFR(Java Flight Recorder):
# 设置 JVM 统一参数:ZGC + JFR 默认开启 + 统一日志格式 [Environment]::SetEnvironmentVariable("JAVA_TOOL_OPTIONS", "-XX:+UseZGC -XX:+FlightRecorder -Xlog:gc*,jfr*=info:stdout:time,tags", "User") $env:JAVA_TOOL_OPTIONS = "-XX:+UseZGC -XX:+FlightRecorder -Xlog:gc*,jfr*=info:stdout:time,tags"参数说明:
-XX:+UseZGC:启用 Z Garbage Collector,低延迟 GC,Windows x64 完整支持;-XX:+FlightRecorder:启用 Java Flight Recorder,用于性能分析;-Xlog:gc*,jfr*=info:stdout:time,tags:将 GC 和 JFR 日志输出到控制台,带时间戳和事件标签,方便调试。
验证是否注入成功:
java -XshowSettings:properties -version 2>&1 | Select-String "java.tool.options" # 应输出: java.tool.options = -XX:+UseZGC -XX:+FlightRecorder ...注意:
JAVA_TOOL_OPTIONS对java命令有效,但对javac、jlink等工具无效。如需为编译器设参数,需在MAVEN_OPTS或 IDE 设置中单独配置。
4. 验证与基础测试:跑通java -version、javac、jshell、jpackage四关
装完不验证,等于没装。我们设计了一套最小闭环测试,覆盖 JDK 21 的核心能力边界,而非简单java -version。每个测试都对应一个真实开发场景,失败即代表环境未就绪。
4.1 第一关:java -version与java -Xinternalversion—— 确认构建来源与功能集
java -version正确输出应包含:
openjdk version "21.0.4" 2024-07-16 OpenJDK Runtime Environment Temurin-21.0.4+7 (build 21.0.4+7) OpenJDK 64-Bit Server VM Temurin-21.0.4+7 (build 21.0.4+7, mixed mode, sharing)关键点:
Temurin字样证明是 Eclipse Temurin 构建,非其他发行版;mixed mode, sharing表示 JVM 支持类共享(Class Data Sharing),提升启动速度;build 21.0.4+7中的+7是构建号,与下载页一致。
更深层验证(确认 ZGC、JFR 等特性已编译进 VM):
java -Xinternalversion输出应含:
OpenJDK 64-Bit Server VM (Temurin-21.0.4+7) for windows-amd64 JRE (11.0.2+7), built on Jul 16 2024 12:34:56 by "jenkins" with MS VC++ 19.35 [2022] ... with ZGC, with JFR, with foreign function & memory API若无with ZGC或with JFR,说明你下的不是 Temurin 官方构建,或 ZIP 损坏。
4.2 第二关:javac --release 21编译与java --enable-preview运行 —— 测试预览特性可用性
JDK 21 的 Virtual Threads 和 Structured Concurrency 是预览特性,需显式启用。写一个最简测试文件HelloVT.java:
// HelloVT.java public class HelloVT { public static void main(String[] args) throws Exception { Thread.ofVirtual().unstarted(() -> { System.out.println("Hello from Virtual Thread!"); }).start(); } }编译(强制目标版本为 21,禁用预览警告):
javac --release 21 --enable-preview --source 21 HelloVT.java运行(必须加--enable-preview):
java --enable-preview HelloVT预期输出:
Hello from Virtual Thread!若报错java.lang.UnsupportedOperationException: Virtual threads are not supported on this platform,说明:
- JVM 未启用 ZGC(Virtual Threads 依赖 ZGC 的线程局部堆);
- 或
JAVA_TOOL_OPTIONS中未设-XX:+UseZGC; - 或你用的是不支持 VT 的构建(如早期 Corretto 21.0.1)。
4.3 第三关:jshell交互式环境 —— 验证模块系统与 REPL 功能
jshell是 JDK 9+ 的交互式 Java Shell,JDK 21 中已完全支持预览特性。启动并测试:
jshell在jshell>提示符下输入:
jshell> /set start DEFAULT jshell> /env --add-modules jdk.incubator.concurrent jshell> var scope = StructuredTaskScope.<String>open(); jshell> scope.fork(() -> "Hello from Structured Concurrency!"); jshell> scope.join(); jshell> /exit若scope.fork报错cannot find symbol,说明jdk.incubator.concurrent模块未加载,需检查jshell启动参数或 JDK 构建完整性。
4.4 第四关:jpackage打包一个最小 GUI 应用 —— 验证 Windows 原生打包能力
jpackage是 JDK 14+ 的原生应用打包工具,JDK 21 Windows x64 支持生成.exe安装包。创建HelloFX.java(JavaFX 最小应用):
// HelloFX.java import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.stage.Stage; public class HelloFX extends Application { @Override public void start(Stage stage) { stage.setScene(new Scene(new Label("Hello from jpackage!"), 300, 100)); stage.show(); } public static void main(String[] args) { launch(args); } }编译并打包:
javac --module-path "%JAVA_HOME%\jmods" --add-modules javafx.controls HelloFX.java jpackage --input . --name HelloFX --main-class HelloFX --main-jar HelloFX.jar --type exe成功后,HelloFX目录下生成HelloFX-1.0.msi和HelloFX-1.0.exe。双击安装,桌面出现快捷方式,点击运行弹出窗口——即证明jpackage、JavaFX 模块、Windows 原生资源绑定全部就绪。
注意:
jpackage依赖WiX Toolset(Windows Installer XML),若提示wix not found,需单独安装 WiX 3.14+,并将其bin目录加入 PATH。这是jpackage在 Windows 上的硬性依赖,无法绕过。
5. 避坑指南:五个真实翻车现场与救火步骤
装 JDK 看似简单,但在 Windows x64 环境下,有五个高频、隐蔽、且文档极少提及的坑。以下是我们在 12 个不同客户环境(从学生机房到金融私有云)中踩出的血泪记录,每条都按「现象 → 原因 → 解决」结构给出可执行方案。
5.1 现象:java -version正常,但mvn clean compile报Fatal error compiling: invalid target release: 21
原因:Maven 的maven-compiler-plugin默认source和target是1.8,即使JAVA_HOME指向 JDK 21,插件仍按旧规则编译。更隐蔽的是,pom.xml中若未声明<properties><maven.compiler.source>21</maven.compiler.source></properties>,Maven 会忽略JAVA_HOME的版本。
解决:
- 方案一(推荐):在项目
pom.xml中添加:<properties> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> <maven.compiler.release>21</maven.compiler.release> </properties> - 方案二:全局设置 Maven
settings.xml(%USERPROFILE%\.m2\settings.xml):<profiles> <profile> <id>jdk21</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> </properties> </profile> </profiles>
5.2 现象:IntelliJ IDEA 识别到 JDK 21,但新建项目时 SDK 列表为空,或新建模块后java.lang.Object报红
原因:IDEA 的 JDK 配置缓存损坏,或project structure中未正确关联Project SDK与Project language level。JDK 21 的语言级别是21 (Preview),若设为21(无 Preview),则virtual thread语法不被识别。
解决:
- 步骤一:
File → Project Structure → Project,Project SDK选D:\jdk21,Project language level必须选21 (Preview); - 步骤二:
File → Project Structure → Modules,选中模块,Sources标签页右上角Language level也设为21 (Preview); - 步骤三:
File → Invalidate Caches and Restart → Invalidate and Restart。
5.3 现象:jps命令查不到任何 Java 进程,但任务管理器中java.exe进程正常运行
原因:jps依赖tools.jar(已移除)和jvm.dll的进程通信协议。Temurin 21 的jps实际调用jcmd,而jcmd需要 JVM 启动时启用jstatd服务或进程间共享内存。Windows 上若 JVM 以SYSTEM账户运行(如 Windows 服务),jps以普通用户运行,则无权访问其共享内存段。
解决:
- 启动 Java 进程时加参数:
-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999; - 或改用
jcmd -l(列出所有 JVM 进程 PID),它比jps更底层、权限要求更低; - 若需
jps全功能,确保 Java 进程与jps命令在同一用户会话下运行(不要用sc create启动服务)。
5.4 现象:jlink生成的运行时镜像,在另一台 Windows 机器上运行报Error: could not find or load main class
原因:jlink默认生成的镜像不包含java.base模块的完整本地化资源(如zh_CN区域设置),当目标机器系统区域为中文时,JVM 初始化失败。Temurin 21 的jlink需显式添加--bind-services和--add-modules。
解决:
# 生成镜像时,强制绑定服务并添加基础模块 jlink --module-path "%JAVA_HOME%\jmods" ` --add-modules java.base,java.desktop,java.logging ` --bind-services ` --output myruntime然后运行myruntime\bin\java -version验证。
5.5 现象:jfr录制的.jfr文件,用 JDK 21 的jfr命令解析时报Invalid JFR file format
原因:jfr录制时若 JVM 启用了ZGC,其事件格式与默认 GC 不同,而jfr命令行工具版本需与录制 JVM 完全一致。若用 JDK 21.0.1 的jfr解析 21.0.4 录制的文件,会因事件 schema 不匹配而失败。
解决:
- 录制与解析必须使用同一构建号的 JDK;
- 或改用
VisualVM(需安装JFR插件)或JDK Mission Control(JMC)图形化工具,它们对版本兼容性更强; - 最佳实践:在 CI 脚本中,用
java -XX:StartFlightRecording=duration=60s,filename=recording.jfr录制,再用同一java命令的jfr子命令解析:java -cp "%JAVA_HOME%\lib\jfr.jar" jdk.jfr.Main print recording.jfr。
6. 验证跑通:用一个 Spring Boot 3.2 WebFlux 应用完成端到端闭环
最后一步,也是最关键的一步:用一个真实框架验证整个 JDK 21 环境是否真正就绪。我们选用Spring Boot 3.2.12(2024-Q3 最新版),因为它强制要求 JDK 21,并深度集成 Virtual Threads 和 Structured Concurrency。这个测试不是为了教你怎么写 Spring,而是检验你的 JDK 是否能支撑现代 Java 生产级应用。
6.1 创建最小可运行项目
用 Spring Initializr(https://start.spring.io/)生成项目,勾选:
- Project: Maven
- Language: Java
- Spring Boot: 3.2.12
- Dependencies: Spring Web, Spring Reactive Web, Lombok(可选)
解压后,编辑pom.xml,确认java.version为21:
<properties> <java.version>21</java.version> </properties>6.2 编写一个 Virtual Thread 驱动的 Controller
替换src/main/java/com/example/demo/DemoApplication.java为:
package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.StructuredTaskScope; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } @RestController class HelloController { private final ThreadFactory virtualThreadFactory = Thread.ofVirtual() .name("vt-", 0) .uncaughtExceptionHandler((t, e) -> System.err.println("VT error: " + e)) .factory(); @GetMapping("/hello") String hello() throws Exception { try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { var task1 = scope.fork(() -> { Thread.sleep(100); return "Hello"; }); var task2 = scope.fork(() -> { Thread.sleep(150); return "World"; }); scope.join(); scope.throwIfFailed(); return task1.get() + " " + task2.get() + " from Virtual Thread!"; } } }6.3 启动与压力测试:用wrk验证 VT 真实效果
编译并启动:
mvn clean package java -jar target/demo-0.0.1-SNAPSHOT.jar此时访问http://localhost:8080/hello应返回:
Hello World from Virtual Thread!关键验证:用wrk(轻量级 HTTP 压测工具)模拟高并发,观察线程数是否爆炸式增长:
# 下载 wrk for Windows(https://github.com/wg/wrk/releases) wrk -t4 -c1000 -d30s http://localhost:8080/hello同时,在另一终端运行:
jcmd -l | findstr "demo" # 得到 PID,例如 12345 jstack 12345 | findstr "vt-" | measure-object -line若jstack输出中vt-线程数远超物理 CPU 核心数(如 1000+),且wrk报告 QPS > 5000,说明 Virtual Threads 已真实启用。若线程数仅 10~20 且 QPS < 1000,则 VT 未生效,需回溯检查JAVA_TOOL_OPTIONS和--enable-preview。
从那以后我每次部署 JDK 21 环境,都强制走一遍这个 Spring Boot +
wrk+jstack三连验证。不是为了炫技,而是因为 JDK 的“版本号”只是纸面承诺,只有在真实流量下撑住 1000 并发的 Virtual Thread,才叫真正落地。希望帮到你。
本文还有配套的精品资源,点击获取