Java 教程说创建线程很昂贵。但究竟为什么它很贵?当创建一个 Java 线程使其创建成本高昂时,究竟发生了什么?我认为这句话是真的,但我只是对 JVM 中的线程创建机制感兴趣。
线程生命周期开销。线程创建和拆卸不是免费的。实际开销因平台而异,但线程创建需要时间,将延迟引入请求处理,并且需要 JVM 和操作系统进行一些处理活动。如果请求频繁且轻量,就像在大多数服务器应用程序中一样,为每个请求创建一个新线程会消耗大量计算资源。
摘自 Java Concurrency in Practice 作者 Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowbeer、David Holmes、Doug Lea 打印 ISBN-10:0-321-34960-1
为什么说创建线程 很 昂贵?
因为它>>是<<昂贵。
Java 线程的创建很昂贵,因为涉及到相当多的工作:
从某种意义上说,只要线程还活着,它就会占用资源,这也是昂贵的。例如线程堆栈、从堆栈可访问的任何对象、JVM 线程描述符、OS 本机线程描述符。
所有这些东西的成本都是特定于平台的,但在我遇到的任何 Java 平台上它们都不便宜。
通过 Google 搜索,我发现了一个旧基准,它报告在运行 2002 复古 Linux 的 2002 复古双处理器 Xeon 上的 Sun Java 1.4.1 上的线程创建速率约为每秒 4000 个。一个更现代的平台将提供更好的数字......我无法评论该方法......但至少它为线程创建可能 有多昂贵提供了一个大概。
Peter Lawrey 的基准测试表明,如今线程创建的绝对速度明显更快,但尚不清楚其中有多少是由于 Java 和/或操作系统的改进......或更高的处理器速度。但是,如果您使用线程池而不是每次创建/启动一个新线程,他的数字 仍然表明提高了 150 倍以上。 (他指出这都是相对的......)
以上假设是原生线程而不是绿色线程,但现代 JVM 出于性能原因都使用原生线程。绿色线程的创建可能更便宜,但您在其他领域需要付费。
更新:OpenJDK Loom 项目旨在为标准 Java 线程提供一种轻量级的替代方案。他们提出了 虚拟线程 ,它是本地线程和绿色线程的混合体。简单来说,虚拟线程就像一个绿色线程实现,当需要并行执行时,它在下面使用本机线程。
截至目前(2021 年 1 月),Project Loom 工作仍处于原型设计阶段,(AFAIK)没有针对发布的 Java 版本。
我已经进行了一些挖掘,以了解 Java 线程的堆栈是如何真正分配的。在 Linux 上的 OpenJDK 6 的情况下,线程堆栈由pthread_create创建本机线程的调用分配。(JVM 不传递pthread_create预先分配的堆栈。)
pthread_create
然后,在pthread_create堆栈内通过调用分配mmap如下:
mmap
mmap(0, attr.__stacksize, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
根据man mmap,该MAP_ANONYMOUS标志使内存初始化为零。
man mmap
MAP_ANONYMOUS
因此,即使新的 Java 线程堆栈归零(根据 JVM 规范)可能不是必需的,但实际上(至少对于 Linux 上的 OpenJDK 6)它们是归零的。