1. 虚拟线程
很长一段时间以来,我们一直在研究非阻塞 IO、异步操作,然后是用于编排异步操作的 Promises 和 Async/Await。因此,我们必须处理回调,并执行诸如 Promises.all()或 之类的操作CompletableFuture.thenCompose()来加入多个异步操作并处理结果。
最近,反应式框架开始将任务“组合”为功能管道,然后在线程池或执行器上运行它们。反应式函数式编程比“回调地狱”要好得多,因此,我们被迫转向函数式编程模型,以便可以以优雅的方式完成非阻塞/异步。
虚拟线程正在结束回调和承诺。Java 团队已经成功地用非常便宜的虚拟线程提供了几乎直接的线程替代品。因此,即使您执行旧的操作,虚拟线程也会分离而不是阻塞。就数量而言,普通笔记本电脑可以执行 2000 到 5000 个线程,而同一台计算机可以执行 100 万个以上的虚拟线程。事实上,官方的建议是避免虚拟线程池化。建议每个任务在新的虚拟线程上运行。虚拟线程支持一切——睡眠、等待、ThreadLocal、锁等。Thread.sleep(5000)
虚拟线程允许我们只编写常规的旧迭代和“看似阻塞”的代码,并让Java分离或附加真实线程,使其变得非阻塞和高性能。然而,我们仍然需要等待像Apache Tomcat和 Spring 这样的库或框架实现者将所有内容从本机线程转移到虚拟线程。一旦框架完成过渡,所有使用这些升级框架的 Java微服务/单体都将自动变为非阻塞。
以我们在应用程序中遇到的一些线程池为例 - Apache Tomcat NIO 有 25 - 50 个工作线程。想象一下 NIO 可以有 50,000 个虚拟线程。Apache Camel 监听器通常有 10-20 个线程。想象一下 Camel 可以有 1000-2000 个虚拟线程。当然,不再有带有虚拟线程的线程池 - 因此,它们将只有无限的 1000 个线程。这几乎彻底结束了 Java 中的“线程饥饿”现象。
只需升级到充分利用 Java 21 的框架/库,我们所有的 Java 微服务都将通过现有代码变得非阻塞。
(注意:一些操作(例如synchronized)也会阻塞虚拟线程。但是,如果我们将它们替换为虚拟线程支持的替代方案(例如)Lock.lock(),那么虚拟线程将能够分离并执行其他任务,直到获取锁为止。为此,库作者需要进行少量代码更改,并且在某些情况下还需要在项目代码库中进行一些更改才能获得虚拟线程的好处)。
2、ZGC
ZGC 现在支持具有永久亚毫秒暂停的 TB 大小的 Java 堆。没有重要的警告...它可能会使用多 5-10% 的内存或慢 5-10% 的分配速度,但不再有停止世界的 GC 暂停,也不再有堆大小限制。
这两项性能改进将共同巩固 Java 在编程语言中的地位。它可能会暂停 Node JS 的主导地位,并在某种程度上暂停响应式编程。反应式或函数式编程可能仍然有利于代码可读性和管理大量事件驱动的应用程序,但我们不再需要反应式编程来在 Java 中执行非阻塞 IO。