内容提要
Java 21引入了多个新功能,包括Foreign Function & Memory API (FFM API),允许Java与本地代码交互。FFM API由Foreign Function Interface (FFI)和Memory API组成。以前使用JNI调用外部函数,但FFM API简化了这个过程。FFM API还提供了一种更安全、更高效的管理非堆内存的方式。Java 21还引入了未命名模式和变量,提高了代码的可读性和可维护性。Java 21的另一个亮点是虚拟线程,允许轻量级并发和更高的吞吐量。作用域值是一个新概念,提供了一种在程序的不同部分之间共享数据而不需要显式参数传递的方式。这些功能旨在简化Java编程并提高性能。
延伸解读
FFM API:JNI 的现代替代方案
文章详细对比了 JNI 和 FFM API。JNI 使用繁琐,需跨语言工具链,丧失跨平台性,且桩代码难维护、不安全、性能差。FFM API 通过 Linker、SymbolLookup 等接口,用纯 Java 代码调用本地函数,无需编写 C 代码,更安全高效。但需注意,FFM API 在 Java 21 中仍是预览版,Java 22 才转正,且部分 API 在 Java 22 有变更,如 Arena::allocateUtf8String 改为 allocateFrom。
内存 API:安全与性能的平衡
文章回顾了 ByteBuffer 和 Unsafe 的局限:ByteBuffer 安全但依赖 GC 释放内存,且容量受限于 2G;Unsafe 高效但危险,可访问任意内存。内存 API 通过 Arena 和 MemorySegment 提供了更安全灵活的方式,支持手动释放和更大内存,适用于大规模数据处理和高性能计算。但 Arena 的生命周期管理需谨慎,错误使用可能导致内存泄漏或访问冲突。
虚拟线程:高吞吐量而非低延迟
虚拟线程是 Java 21 的正式特性,由 JVM 调度,可大幅提升 I/O 密集型任务的吞吐量。文章示例中,10 万个虚拟线程仅需 1.5 秒完成,而平台线程池需 50 秒。但虚拟线程不适用于计算密集型任务,因为其运行速度与平台线程无异。虚拟线程无需池化,创建成本极低,但调试工具如 jcmd 已支持 JSON 格式转储,便于分析大量虚拟线程。
作用域值:线程本地变量的改进
作用域值解决了 ThreadLocal 的可变性、无限生命周期和继承开销问题。它不可变,仅在 run() 方法内有效,且父线程绑定可被结构化并发子线程继承,无需复制,内存开销小。但作用域值不支持重新赋值,只能通过 where() 重新绑定。与 ThreadLocal 相比,作用域值更安全,尤其适合虚拟线程场景,避免内存泄漏。
Q&A
Java 21引入了哪些主要的新特性?
Java 21引入了外部函数和内存API、未命名模式和变量、虚拟线程、作用域值等新特性。
什么是外部函数和内存API(FFM API)?
FFM API是Java 21中的一个特性,允许Java与本地代码交互,由外部函数接口(FFI)和内存API组成,简化了JNI的使用。
虚拟线程在Java 21中有什么优势?
虚拟线程允许轻量级并发,显著提高系统吞吐量,适用于I/O密集型任务,能够在较少的平台线程上运行大量虚拟线程。
未命名模式和变量的主要用途是什么?
未命名模式和变量旨在提高代码的可读性和可维护性,允许开发者省略不需要的变量名称。
作用域值(Scoped Values)如何改善数据共享?
作用域值提供了一种隐式方法参数的形式,允许在程序的不同部分之间安全地共享数据,而无需显式参数传递,避免了线程本地变量的缺陷。
FFM API与JNI相比有什么优势?
FFM API提供了更优雅的本地函数调用方式,简化了JNI的繁琐过程,并且在安全性和性能上都有显著提升。