我正在参与「启航方案」
➜ 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 下载:jdk.java.net/19/
Java 20 OpenJDK 文档:openjdk.java.net/projects/jd…
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/java….
文章持续更新,能够微信搜一搜「 程序猿阿朗 」或拜访「程序猿阿朗博客 」第一时刻阅读。本文 Github.com/niumoo/Java… 现已收录,有许多系列文章,欢迎Star。