JDK19
JDK 19 2022 年 9 月 20 日正式发布以供生产使用,非长期支持版本。不过,JDK 19 中有一些比较重要的新特性值得关注。开始有虚拟线程了
特性列表
Record Patterns (Preview)
对于record的 instanceof的模式匹配
record Point(int x, int y) {}
//old
static void printSum(Object o) {
if (o instanceof Point p) {
int x = p.x();
int y = p.y();
System.out.println(x+y);
}
}
// new
static void printSum(Object o) {
if (o instanceof Point p) {
int x = p.x();
int y = p.y();
System.out.println(x+y);
}
}
// 泛型
record Box<T>(T t) {}
static void test1(Box<Object> bo) {
if (bo instanceof Box<Object>(String s)) {
System.out.println("String " + s);
}
}
static void test2(Box<Object> bo) {
if (bo instanceof Box<String>(var s)) {
System.out.println("String " + s);
}
}
static void erroneousTest1(Box<Object> bo) {
if (bo instanceof Box(var s)) { // Error
System.out.println("I'm a box");
}
}
static void erroneousTest2(Box b) {
if (b instanceof Box(var t)) { // Error
System.out.println("I'm a box");
}
}
JEP 422: Linux/RISC-V Port
Linux/RISC-V 移植
JEP 424: Foreign Function & Memory API (Preview)
之前的incubator 变成preview API了;
例子
使用FFM API的一个简短示例,下面是Java代码,它获取C库函数radixsort的方法句柄,然后使用它对四个字符串进行排序,这些字符串在Java数组中开始运行(省略了一些细节)。因为FFM API是一个预览API,你必须在启用预览特性的情况下编译和运行代码,例如,javac——release 19——enable-preview…Java——enable-preview …
// 1. Find foreign function on the C library path
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle radixSort = linker.downcallHandle(
stdlib.lookup("radixsort"), ...);
// 2. Allocate on-heap memory to store four strings
String[] javaStrings = { "mouse", "cat", "dog", "car" };
// 3. Allocate off-heap memory to store four pointers
SegmentAllocator allocator = SegmentAllocator.implicitAllocator();
MemorySegment offHeap = allocator.allocateArray(ValueLayout.ADDRESS, javaStrings.length);
// 4. Copy the strings from on-heap to off-heap
for (int i = 0; i < javaStrings.length; i++) {
// Allocate a string off-heap, then store a pointer to it
MemorySegment cString = allocator.allocateUtf8String(javaStrings[i]);
offHeap.setAtIndex(ValueLayout.ADDRESS, i, cString);
}
// 5. Sort the off-heap data by calling the foreign function
radixSort.invoke(offHeap, javaStrings.length, MemoryAddress.NULL, '\0');
// 6. Copy the (reordered) strings from off-heap to on-heap
for (int i = 0; i < javaStrings.length; i++) {
MemoryAddress cStringPtr = offHeap.getAtIndex(ValueLayout.ADDRESS, i);
javaStrings[i] = cStringPtr.getUtf8String(0);
}
assert Arrays.equals(javaStrings, new String[] {"car", "cat", "dog", "mouse"}); // true
JEP 425: Virtual Threads (Preview)
向Java平台引入虚拟线程。虚拟线程是轻量级线程,可以显著减少编写、维护和观察高吞吐量并发应用程序的工作量。这是一个预览API。
最重要的特性,这个特性得开个单个文章讲
使用例子
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return i;
});
});
} // executor.close() is called implicitly, and waits
// 或者
Thread thread = Thread.ofVirtual().name("duke").unstarted(runnable);
JEP 426: Vector API (Fourth Incubator)
向量api,继续Incubator
JEP 427: Pattern Matching for switch (Third Preview)
扩展大小写标签,除常量外,还包括模式和null;
扩展switch语句和switch表达式的选择器表达式允许的类型范围,以及允许可选的when子句跟在case标签后面。
为方便起见,我们还引入了带括号的模式。
// old
static void testFooBar(String s) {
if (s == null) {
System.out.println("Oops!");
return;
}
switch (s) {
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
// new
static void testFooBar(String s) {
switch (s) {
case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
JEP 428: Structured Concurrency (Incubator)
通过引入结构化并发的API来简化多线程编程。结构化并发将在不同线程中运行的多个任务视为单个工作单元,从而简化了错误处理和取消,提高了可靠性并增强了可观察性。这是一个正在孵化的API。
Response handle() throws ExecutionException, InterruptedException {
Future<String> user = esvc.submit(() -> findUser());
Future<Integer> order = esvc.submit(() -> fetchOrder());
String theUser = user.get(); // Join findUser
int theOrder = order.get(); // Join fetchOrder
return new Response(theUser, theOrder);
}
但是当findUser抛出异常时,fetchOrder还是会在自己的线程继续运行,或者findUser需要运行很长时间,而当fetchOrder异常时,整个handle方法还是需要浪费时间等待findUser执行完,它阻塞在user.get()。为了更好地处理这种在异常场景下取消其他子任务,引入结构化并发来解决此问题,其主要是StructuredTaskScope这个类,它可以fork子任务,然后一起join或者一起cancel。
Response handle() throws ExecutionException, InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> user = scope.fork(() -> findUser());
Future<Integer> order = scope.fork(() -> fetchOrder());
scope.join(); // Join both forks
scope.throwIfFailed(); // ... and propagate errors
// Here, both forks have succeeded, so compose their results
return new Response(user.resultNow(), order.resultNow());
}
}
如果其中一个子任务失败了,则会取消另外一个在运行的任务。在scope.join()之后,可以使用resultNow()或者exceptionNow()来获取结果