共计 7014 个字符,预计需要花费 18 分钟才能阅读完成。
➜ bin pwd | |
/Users/darcy/develop/jdk-20.0.1.jdk/Contents/Home/bin | |
➜ bin ./java -version | |
openjdk version "20.0.1" 2023-04-18 | |
OpenJDK Runtime Environment (build 20.0.1+9-29) | |
OpenJDK 64-Bit Server VM (build 20.0.1+9-29, mixed mode, sharing) |
Java 20 共带来 7 个新个性性能,其中三个是孵化提案,孵化也就是说尚在征求意见阶段,将来可能会删除此性能。
JEP | 形容 | 分类 |
---|---|---|
429 | 作用域值(孵化器) | Project Loom,Java 开发相干 |
432 | Record 模式匹配(第二次预览) | Project Amber,新的语言个性 |
433 | switch 的模式匹配(第四次预览) | Project Amber,新的语言个性 |
434 | 内部函数和内存 API(第二个预览版) | Project Panama,非 Java 库 |
436 | 虚构线程(第二个预览版) | Project Loom,Java 开发相干 |
437 | 结构化并发(第二孵化器) | Project Loom,Java 开发相干 |
438 | Vector API(第五孵化器) | Project Panama,非 Java 库 |
JEP:JDK Enhancement Proposal,JDK 加强倡议,或者叫 Java 将来倒退倡议。
JDK 20 不是长期反对 (LTS) 版本,因而它只会在六个月后被 JDK 21 取代之前收到更新。JDK 17(2021 年 9 月 14 日公布)是 Java 的最新 LTS 版本。Oracle 发表打算将 LTS 版本之间的工夫从三年缩短到两年,因而 JDK 21(2023 年 9 月)打算成为下一个 LTS。
Java 20 装置
Java 20 OpenJDK 下载:https://jdk.java.net/19/
Java 20 OpenJDK 文档:https://openjdk.java.net/projects/jdk/20/
Java 20 OracleJDK 下载:Oracle JDK 20 Archive Downloads
# 此文中示例代码运行都在 Java 20 环境下应用命令 | |
➜ src $ /jdk-20.0.1.jdk/Contents/Home/bin/java --version | |
openjdk 20.0.1 2023-04-18 | |
OpenJDK Runtime Environment (build 20.0.1+9-29) | |
OpenJDK 64-Bit Server VM (build 20.0.1+9-29, mixed mode, sharing) | |
➜ src $ /jdk-20.0.1.jdk/Contents/Home/bin/java --add-modules jdk.incubator.concurrent Xxx.java | |
WARNING: Using incubator modules: jdk.incubator.concurrent | |
hello wdbyte | |
没有信息 |
JEP 429: Scoped Value
在线程之间 共享变量 不是一件简略的事,能够应用 ThreadLocal
来保留以后线程变量,然而须要手动清理,开发者经常遗记,且变量不能被子线程继承;而应用 InheritableThreadLocal
共享信息能够被子线程继承,然而数据会拷贝多份,占用更多内存。
引入 Scoped values
, 容许在线程内和线程间共享不可变数据,这比线程局部变量更加不便,尤其是在应用大量虚构线程时。这进步了易用性、可了解性、健壮性以及性能。不过这是一个正在孵化的 API,将来可能会被删除。
scoped values
有上面几个指标:
- 易用性——提供一个编程模型来在线程内和子线程之间共享数据,从而简化数据流的推理。
- 可了解性——使共享数据的生命周期从代码的句法结构中可见。
- 稳健性——确保调用者共享的数据只能由非法的被调用者检索。
- 性能——将共享数据视为不可变的,以便容许大量线程共享,并启用运行时优化。
例子
如果每个申请都是用一个独自的线程来解决,当初须要承受一个申请,而后依据不同身份拜访数据库,那么咱们能够用传递参数的形式,间接把身份信息在调用拜访数据库办法时传递过来。如果不这么做,那么就要应用 ThreadLocal
来共享变量了。
Thread 1 Thread 2 | |
-------- -------- | |
8. 数据库 - 开始查问 () 8. throw new InvalidPrincipalException() | |
7. 数据库 - 开始拜访 () <---+ 7. 数据库 - 开始拜访 () <---+ | |
... | ... | | |
... 身份(管理员) ... 身份(访客) | |
2. 开始解决(..) | 2. 开始解决(..) | | |
1. 收到申请(..) -----------+ 1. 收到申请(..) -----------+ |
示意代码:
class Server {final static ThreadLocal<Principal> PRINCIPAL = new ThreadLocal<>(); | |
void serve(Request request, Response response) {var level = (request.isAuthorized() ? ADMIN : GUEST); | |
var principal = new Principal(level); | |
PRINCIPAL.set(principal); | |
Application.handle(request, response); | |
} | |
} | |
class DBAccess {DBConnection open() {var principal = Server.PRINCIPAL.get(); | |
if (!principal.canOpen()) throw new InvalidPrincipalException(); | |
return newConnection(...); | |
} | |
} |
这是咱们常见的写法,然而应用 ThreadLocal
的问题是:
PRINCIPAL.set(principal)
能够被任意设置批改。- 应用
ThreadLocal
可能会遗记remove
。 - 如果想要子线程继承共享的变量,须要占用新的内存空间。
- 在虚构线程场景下,可能会有几十万线程,应用
ThreadLocal
过于简单,且有平安性能隐患。
虚构线程自 Java 19 引入:JEP 425: 虚构线程 (预览)
应用 ScopedValue
import jdk.incubator.concurrent.ScopedValue; | |
/** | |
* 启动命令加上 --add-modules jdk.incubator.concurrent | |
* | |
* @author https://www.wdbyte.com | |
*/ | |
public class Jep429ScopedValueTest {final static ScopedValue<String> SCOPED_VALUE = ScopedValue.newInstance(); | |
public static void main(String[] args) { | |
// 创立线程 | |
Thread thread1 = new Thread(Jep429ScopedValueTest::handle); | |
Thread thread2 = new Thread(Jep429ScopedValueTest::handle); | |
String str = "hello wdbyte"; | |
// 传入线程里应用的字符串信息 | |
ScopedValue.where(SCOPED_VALUE, str).run(thread1); | |
ScopedValue.where(SCOPED_VALUE, str).run(thread2); | |
// 执行结束主动清空,这里获取不到了。System.out.println(SCOPED_VALUE.orElse("没有信息")); | |
} | |
public static void handle() {String result = SCOPED_VALUE.get(); | |
System.out.println(result); | |
} | |
} |
运行:
➜ src $ /jdk-20.0.1.jdk/Contents/Home/bin/java --version | |
openjdk 20.0.1 2023-04-18 | |
OpenJDK Runtime Environment (build 20.0.1+9-29) | |
OpenJDK 64-Bit Server VM (build 20.0.1+9-29, mixed mode, sharing) | |
➜ src $ /jdk-20.0.1.jdk/Contents/Home/bin/java --add-modules jdk.incubator.concurrent Jep429ScopedValueTest.java | |
WARNING: Using incubator modules: jdk.incubator.concurrent | |
hello wdbyte.com | |
hello wdbyte.com | |
没有信息 |
可见应用 ScopedValue
有几个不言而喻的益处。
- 代码不便,容易了解。合乎编程逻辑。
- 不容许批改值,安全性高。(没有 set 办法)
- 生命周期明确。只传递到
run()
办法体中。 - 不须要清理,主动开释。
- 从实现来讲,也是一种轻量级实现。
JEP 432: Record 模式匹配(二次预览)
在 Java 14 的 JEP 359 中减少了 Record 类,在 Java 16 的 JEP 394 中,新增了 instanceof 模式匹配。
这两项都简化了 Java 开发的代码编写。在 Java 19 的 JEP 405 中,增又加了 Record 模式匹配性能的第一次预览,这把 JEP 359 和 JEP 394 的性能进行了联合,然而还不够弱小,当初 JEP 432 又对其进行了加强。
JEP 359 性能回顾:
/** | |
* @author https://www.wdbyte.com | |
*/ | |
public class RecordTest {public static void main(String[] args) {Dog dog = new Dog("name", 1); | |
System.out.println(dog.name()); // name | |
System.out.println(dog.age()); // 1 | |
} | |
} | |
record Dog(String name, Integer age) {} |
JEP 394 性能回顾:
// Old code | |
if (obj instanceof String) {String s = (String)obj; | |
... use s ... | |
} | |
// New code | |
if (obj instanceof String s) {... use s ...} |
JEP 432 例子
而当初,能够进行更加简单的组合嵌套,仍旧能够精确辨认类型。
/** | |
* @author https://www.wdbyte.com | |
*/ | |
public class Jep432RecordAndInstance {public static void main(String[] args) {ColoredPoint coloredPoint1 = new ColoredPoint(new Point(0, 0), Color.RED); | |
ColoredPoint coloredPoint2 = new ColoredPoint(new Point(1, 1), Color.GREEN); | |
Rectangle rectangle = new Rectangle(coloredPoint1, coloredPoint2); | |
printUpperLeftColoredPoint(rectangle); | |
} | |
static void printUpperLeftColoredPoint(Rectangle r) {if (r instanceof Rectangle(ColoredPoint ul, ColoredPoint lr)) {System.out.println(ul.c()); | |
} | |
} | |
} | |
record Point(int x, int y) {} | |
enum Color {RED, GREEN, BLUE} | |
record ColoredPoint(Point p, Color c) {} | |
record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {} |
输入:RED
。
JEP 433: switch 模式匹配(四次预览)
Switch 的应用体验革新早在 Java 17 就曾经开始了,上面是之前文章的一些介绍。
- JEP 406:switch 的类型匹配(预览)
- JEP 420:switch 表达式(二次预览)
- JEP 427: switch 模式匹配 (三次预览)
当初 JEP 433 进行第四次预览,对其性能进行了加强,间接从上面的新老代码看其变动。
/** | |
* @author https://www.wdbyte.com | |
*/ | |
public class JEP433SwitchTest {public static void main(String[] args) { | |
Object obj = 123; | |
System.out.println(matchOld(obj)); // 是个数字 | |
System.out.println(matchNew(obj)); // 是个数字 | |
obj = "wdbyte.com"; | |
System.out.println(matchOld(obj)); // 是个字符串,长度大于 2 | |
System.out.println(matchNew(obj)); // 是个字符串,长度大于 2 | |
} | |
/** | |
* 老代码 | |
* | |
* @param obj | |
* @return | |
*/ | |
public static String matchOld(Object obj) {if (obj == null) {return "数据为空";} | |
if (obj instanceof String) {String s = obj.toString(); | |
if (s.length() > 2) {return "是个字符串,长度大于 2";} | |
if (s.length() <= 2) {return "是个字符串,长度小于等于 2";} | |
} | |
if (obj instanceof Integer) {return "是个数字";} | |
throw new IllegalStateException("未知数据:" + obj); | |
} | |
/** | |
* 新代码 | |
* | |
* @param obj | |
* @return | |
*/ | |
public static String matchNew(Object obj) {String res = switch (obj) { | |
case null -> "数据为空"; | |
case String s when s.length() > 2 -> "是个字符串,长度大于 2"; | |
case String s when s.length() <= 2 -> "是个字符串,长度小于等于于 2"; | |
case Integer i -> "是个数字"; | |
default -> throw new IllegalStateException("未知数据:" + obj); | |
}; | |
return res; | |
} | |
} |
JEP 434: 内部函数和内存 API(二次预览)
此性能引入的 API 容许 Java 开发者与 JVM 之外的代码和数据进行交互,通过调用内部函数(JVM 之外)和平安的拜访内部内存(非 JVM 治理),让 Java 程序能够调用本机库并解决本机数据,而不会像 JNI 一样存在很多平安危险。
这不是一个新性能,自 Java 14 就曾经引入,此次对其进行了性能、通用性、安全性、易用性上的优化。
历史
- Java 14 JEP 370 引入了内部内存拜访 API(孵化器)。
- Java 15 JEP 383 引入了内部内存拜访 API(第二孵化器)。
- Java 16 JEP 389 引入了内部链接器 API(孵化器)。
- Java 16 JEP 393 引入了内部内存拜访 API(第三孵化器)。
- Java 17 JEP 412 引入了内部函数和内存 API(孵化器)。
- Java 18 JEP 419 引入了内部函数和内存 API(二次孵化器)。
- Java 19 JEP 424 引入了内部函数和内存 API(孵化器)。
JEP 436: 虚构线程(二次预览)
通过将轻量级虚构线程引入 Java 平台,简化了编写、保护和察看高吞吐量、并发应用程序的过程。使开发人员可能应用现有的 JDK 工具和技术轻松地排除故障、调试和剖析并发应用程序,虚构线程有助于减速利用程序开发。
这个个性自 Java 19 的 JEP 425: 虚构线程 (预览)引入,在 Java 19 曾经进行了具体介绍。
JEP 425: 虚构线程 (预览)
JEP 437: Structured Concurrency(二次孵化)
通过引入用于结构化并发 API 来简化多线程编程。结构化并发将在不同线程中运行的多个工作视为单个工作单元,从而简化错误处理,进步可靠性,加强可察看性。因为是个孵化状态提案,这里不做过多钻研。
- 相干 Java 19,JEP 428:结构化并发(孵化)
JEP 438: Vector API(五次孵化)
再次进步性能,实现优于等效标量计算的性能。这是通过引入一个 API 来表白矢量计算,该 API 在运行时牢靠地编译为反对的 CPU 架构上的最佳矢量指令,从而实现优于等效标量计算的性能。Vector API 在 JDK 16 到 19 中孵化。JDK 20 整合了这些版本用户的反馈以及性能改良和实现加强。
判若两人,文章中代码寄存在 Github.com/niumoo/javaNotes.
文章继续更新,能够微信搜一搜「程序猿阿朗」或拜访「程序猿阿朗博客」第一工夫浏览。本文 Github.com/niumoo/JavaNotes 曾经收录,有很多系列文章,欢送 Star。