Java 19 新功能介绍( 二 )


看到这里你可能要说了,可以放弃请求和线程一一对应的方式啊,使用异步编程来解决这个问题,把请求处理分段,在组合成顺序管道,通过一套 API 进行管理,这样就可以使用有限的线程来处理超过线程数量的请求 。这当然也是可以的,但是随之而来的问题是:

  • 需要额外的学习异步编程 。
  • 代码复杂度增加,等于放弃了语言的基本顺序组合运算 。
  • 堆栈上下文信息都变得难以追踪 。
  • Debug 困难 。
  • 和 Java 平台本身的编程风格有冲突,Java 并发单元是 Thread,而这时是异步管道 。
虚拟线程基于上面的种种原因,Java 19 引入了虚拟线程,在使用体验上和 Thread 没有区别,与之前的 API 互相兼容,但是相比之下虚拟线程资源占用非常少,同时优化了硬件的使用效率,因此非常易用且不需要被池化 。
下面是一个示例,创建 10 万个线程,然后都休眠 1 秒钟最后打印耗时,如果是开传统的 Thread 线程的方式,资源十分紧张;如果是线程池的方式,必定有部分线程在等待线程释放;但是使用虚拟线程的方式,可以瞬间完成 。
import java.util.concurrent.Executors;import java.util.stream.IntStream;public class ThreadTest {public static void main(String[] args) {long start = System.currentTimeMillis();try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {IntStream.range(0, 100_000).forEach(i -> {executor.submit(() -> {Thread.sleep(1000);return i;});});} // executor.close() 会被自动调用// 提交了 10 万个虚拟线程,每个线程休眠 1 秒钟,1秒左右完成System.out.println("耗时:" + (System.currentTimeMillis() - start)+"ms");}}执行后发现 1.3 秒执行完毕,速度惊人 。
【Java 19 新功能介绍】?bin ./java --enable-preview --source 19ThreadTest.java注: ThreadTest.java 使用 Java SE 19 的预览功能 。注: 有关详细信息,请使用 -Xlint:preview 重新编译 。耗时:1309ms?bin注意:虚拟线程只是增加程序的吞吐量,并不能提高程序的处理速度 。
JEP 427: switch 模式匹配 (三次预览)Switch 模式匹配在 Java 17 中已经引入,在 Java 18 中二次预览,现在在 Java 19 中进行三次预览,功能和在 Java 18 新功能介绍 - Switch 中介绍的一样,改进后的 Switch 模式匹配可以代码更加简洁,逻辑更加清晰,下面是一些使用示例对比 。
下面是几个例子:
// JDK 17 以前static String formatter(Object o) {String formatted = "unknown";if (o instanceof Integer i) {formatted = String.format("int %d", i);} else if (o instanceof Long l) {formatted = String.format("long %d", l);} else if (o instanceof Double d) {formatted = String.format("double %f", d);} else if (o instanceof String s) {formatted = String.format("String %s", s);}return formatted;}而在 Java 17 之后,可以通过下面的写法进行改进:
// JDK 17 之后static String formatterPatternSwitch(Object o) {return switch (o) {case Integer i -> String.format("int %d", i);case Long l-> String.format("long %d", l);case Double d-> String.format("double %f", d);case String s-> String.format("String %s", s);default-> o.toString();};}switch 可以和 null 进行结合判断:
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");}}case 时可以加入复杂表达式:
static void testTriangle(Shape s) {switch (s) {case Triangle t && (t.calculateArea() > 100) ->System.out.println("Large triangle");default ->System.out.println("A shape, possibly a small triangle");}}case 时可以进行类型判断:
sealed interface S permits A, B, C {}final class A implements S {}final class B implements S {}record C(int i) implements S {}// Implicitly finalstatic int testSealedExhaustive(S s) {return switch (s) {case A a -> 1;case B b -> 2;case C c -> 3;};}

经验总结扩展阅读