并行(Parallel)指多GC线程同时工作但用户线程全程暂停(STW),目标是高吞吐量;并发(Concurrent)指GC线程与用户线程交替或重叠执行,仅短暂STW,目标是低延迟。

“Parallel”和“Concurrent”在 JVM 垃圾回收中不是同义词,也不是程度差异,而是两类根本不同的协作关系——关键看 GC 线程和用户线程是否同时运行。
并行(Parallel):多 GC 线程干活,但用户必须等
并行指的是多个 GC 线程之间并行执行,比如用 4 个线程一起扫描、复制或整理对象。但整个过程用户线程全程冻结(STW),业务完全停摆。
- 典型收集器:Parallel Scavenge(新生代)、Parallel Old(老年代)、ParNew
- 目标明确:最大化吞吐量(即单位时间里用户代码运行占比最高)
- 适合场景:后台批处理、离线计算、对响应延迟不敏感的服务
- 注意:开启 -XX:+UseParallelGC 后,默认新生代和老年代都走并行路径
并发(Concurrent):GC 和用户线程抢着跑,不锁死应用
并发是指 GC 线程与用户线程在时间上重叠执行——不是“完全不暂停”,而是在多数阶段允许用户线程继续运行,仅在极少数必要环节(如初始标记、重新标记)触发短暂 STW。
- 典型收集器:CMS(已废弃)、G1(默认启用并发模式)、ZGC、Shenandoah
- 目标明确:最小化单次停顿时间(pause time),保障响应性
- 代价存在:需额外内存开销(如写屏障、记忆集)、CPU 时间被 GC 分流、吞吐量略低于 Parallel
- 适用场景:Web API、实时交易、交互式应用等低延迟敏感系统
串行(Serial)是并行的“单核版”,不是并发的简化版
Serial 是最基础的单线程 GC,同样全程 STW,只是不用多线程。它和 Concurrent 没有演化关系——Serial 和 Parallel 是“是否用多线程加速 STW”的关系;而 Concurrent 是“能否避免全程 STW”的范式转变。
- Serial / Serial Old:默认用于 Client 模式或小堆(
- 不能因为“Serial 是单线程”就认为“Concurrent 是多线程优化”,这是常见误解
- 真正和 Concurrent 对应的参照系,是“是否允许用户线程与 GC 线程并发活动”
选 Parallel 还是 Concurrent?看核心指标取舍
没有绝对优劣,只有目标导向:吞吐量优先选 Parallel;延迟敏感选 Concurrent。现代生产环境更倾向 G1 或 ZGC,因它们在可控停顿前提下兼顾一定吞吐能力。
- 吞吐量 = 用户代码运行时间 /(用户代码运行时间 + GC 时间)→ Parallel 更高
- 最大停顿时间(Max Pause Time)→ Concurrent 显著更低(G1 可设 -XX:MaxGCPauseMillis=200)
- 注意:Concurrent 不等于零停顿,G1 的 Mixed GC、ZGC 的部分阶段仍有微秒级 STW










