Java的虚拟线程(协程)特性处于预览阶段,多线程开发难度将大大降低。Java开发人员也一直在尝试使用多线程来解决应用服务器中的并发问题。但是多线程并不容易,所以出现了一种新技术,就是虚拟线程。传统多线程的痛点但是编写多线程代码并不容易,执行顺序难以控制、共享变量的线程安全、异常的可观察性等都是多线程编程的难点。如果在请求期间每个请求都在一个线程中处理,那么为了提高应用程序的吞吐量,线程数必须随着吞吐量的增加而增加。不幸的是线程是一种稀缺资源,创建一个线程代价高昂,即使引入池化技术也无法降低创建新线程的成本,而且JDK目前的线程实现将应用程序吞吐量限制在远低于硬件所能支持的水平。为此,很多开发者转向了异步编程,比如CompletableFuture或者现在火热的反应式框架。但这些技术要么无法摆脱“回调地狱”,要么缺乏可观察性。需要解决这些痛点,增强Java平台的和谐性,对每个请求实现thread-per-request风格。能否将“低成本”的虚拟线程映射到系统线程,减少对系统线程的直接操作?思路应该没问题!于是Java社区发起了关于虚拟线程的JEP425提案。Virtualthreads虚拟线程(virtualthreads)应该是非常廉价的,可以不用担心系统硬件资源被大量创建,不应该被池化。应为每个应用程序任务创建一个新的虚拟线程。因此,大多数虚拟线程都是短暂的并且具有浅调用堆栈,仅执行单个任务HTTP客户端调用或单个JDBC查询。对应的平台线程(PlatformThreads,现在是传统的JVM线程)是重量级的,开销很大,所以通常需要池化。它们往往是长期存在的,具有很深的调用堆栈,并且在许多任务之间共享。总之,虚拟线程在优化硬件利用率的同时,保留了与Java平台设计一致的可靠的thread-per-request风格。使用虚拟线程不需要学习新概念,甚至需要改掉目前操作多线程的习惯。它使用更易用的API,兼容以往的多线程设计,完全不影响代码的可扩展性。平台线程和虚拟线程的区别为了更好地理解这种设计,草案比较了两种类型的线程。现在的线程每个java.lang.Thread现在都是一个平台线程,平台线程在底层操作系统线程上运行Java代码,并在代码的整个生命周期内捕获操作系统线程。平台线程数受操作系统线程数限制。平台线程不会因为虚拟线程的加入而退出历史舞台。未来的虚拟线程虚拟线程是JDK而不是操作系统提供的线程的轻量级实现。它们是用户态线程的一种形式,已成功用于其他多线程语言(如Golang中的协程和Erlang中的进程)。虚拟线程采用M:N调度,其中大量(M)虚拟线程被安排在较少数量(N)的操作系统线程上运行。JDK的虚拟线程调度程序是一种以FIFO模式运行的ForkJoinPool工作窃取机制。我们可以随意创建10000个虚拟线程://预览代码.sleep(Duration.ofSeconds(1));returni;});});}不用担心硬件资源能不能搞定。反之,如果使用Executors.newCachedThreadPool()创建10000个平台线程,在large大多数操作系统上很容易因为资源不足而崩溃。为吞吐量而设计但是这里还是有必要说明一下,虚拟线程并不是为了提高执行速度而设计的。它并不比平台线程快,它们的存在是为了提供规模(更高的吞吐量),而不是速度(更低的延迟)。它们的数量可能比平台线程多得多,因此根据Little定律,它们可以实现更高吞吐量所需的更高并发性。换句话说,当并发任务的数量很高(超过几千)并且工作负载不受CPU限制时,虚拟线程可以显着提高应用程序吞吐量,因为在这种情况下,处理器内核的数量远多于线程不会提高吞吐量。虚拟线程有助于提高传统服务器应用程序的吞吐量,因为此类应用程序包含大量并发任务,这些任务需要花费大量时间等待。增强可观察性编写干净的代码并不是它的全部。清楚地表示正在运行的程序的状态对于故障排除、维护和优化也很重要,并且JDK长期以来一直提供调试、分析和监视线程的机制。处于虚拟线程中还增强了代码的可观察性,使开发人员能够更好地调试代码。新的线程API为此增加了新的线程API设计,目前发布的部分如下:Thread.Builder线程生成器。ThreadFactory可以批量构建具有相同特性的线程工厂。Thread.ofVirtual()创建一个虚拟线程。Thread.ofPlatform()创建一个平台线程。Thread.startVirtualThread(Runnable)一种创建并启动虚拟线程的简便方法。Thread.isVirtual()测试线程是否为虚拟线程。还有很多我就不一一展示了。有兴趣的可以自行去看JEP425。综上所述,JEP425的细节还是很多的。以我个人理解的不足,只能解读这么多。协程在Java社区呼声已久,如今终于有了实质性的动作。这是令人振奋的好消息。不过这个函数涉及的东西还是很多的,包括平台线程兼容性,对ThreadLocal的一些影响,对JUC的影响。可能需要多次预览才能最终落地。那个时候胖哥可能赶不上,但是很多年轻学员应该可以赶上。关注公众号:Felordcn获取更多资讯个人博客:https://felord.cn
