一、线程栈相关参数

1.1 -Xss:线程栈大小

# 默认值(不同平台不同)
# Linux/macOS:1MB
# Windows:根据虚拟内存

# 设置线程栈大小
-Xss512k    # 设置为512KB
-Xss1m      # 设置为1MB(推荐)
-Xss2m      # 设置为2MB

作用

  • 控制每个线程的栈内存大小
  • 栈用于存储局部变量、方法调用链

调优建议

// ❌ 栈太小:StackOverflowError
-Xss128k  // 递归深度受限

// ❌ 栈太大:可创建线程数少
-Xss10m   // 内存浪费,线程数受限

// ✅ 推荐配置
-Xss1m    // 平衡性能和内存

计算可创建线程数

最大线程数 = (最大进程内存 - JVM堆内存 - JVM非堆内存) / 线程栈大小

例如:
- 最大进程内存:4GB
- JVM堆内存:2GB
- JVM非堆内存:512MB
- 线程栈大小:1MB

最大线程数 = (4GB - 2GB - 512MB) / 1MB ≈ 1536个线程

二、锁优化相关参数

2.1 偏向锁

# 启用偏向锁(JDK 8默认启用)
-XX:+UseBiasedLocking

# 禁用偏向锁
-XX:-UseBiasedLocking

# 偏向锁延迟启动时间(默认4秒)
-XX:BiasedLockingStartupDelay=0  # 立即启用

偏向锁原理

// 场景:单线程反复获取同一个锁
synchronized (lock) {
    // 第一次加锁:记录线程ID(偏向)
    // 后续加锁:直接通过,无需CAS
}

// 优势:无锁竞争时,性能提升10倍
// 劣势:有锁竞争时,需要撤销偏向,性能下降

调优建议

# 单线程或低竞争:启用偏向锁
-XX:+UseBiasedLocking

# 高竞争场景:禁用偏向锁
-XX:-UseBiasedLocking

# JDK 15+:偏向锁已弃用

2.2 自旋锁

# 启用自旋锁(默认启用)
-XX:+UseSpinning

# 自旋次数(JDK 6+已废弃,改为自适应)
-XX:PreBlockSpin=10

# 自适应自旋
-XX:+UseSpinning  # 自动调整自旋次数

自旋锁原理

// 传统加锁:直接阻塞线程(用户态 → 内核态)
// 自旋锁:先自旋等待(用户态),避免切换

// 场景:锁持有时间短(几微秒)
while (!tryLock()) {
    // 自旋等待(空循环)
}

// 优势:避免线程切换,性能提升
// 劣势:锁持有时间长时,浪费CPU

2.3 轻量级锁

# 轻量级锁(默认启用)
-XX:+UseLightweightLocking  # JDK 15+

轻量级锁原理

无锁 → 偏向锁 → 轻量级锁 → 重量级锁

- 偏向锁:单线程场景,无CAS
- 轻量级锁:低竞争场景,CAS加锁
- 重量级锁:高竞争场景,操作系统互斥锁

三、GC相关线程参数

3.1 并行GC线程数

# 并行GC线程数(默认:CPU核心数)
-XX:ParallelGCThreads=8

# 计算公式(多核)
ParallelGCThreads = CPU核心数

# 计算公式(超过8核)
ParallelGCThreads = 8 + (CPU核心数 - 8) * 5/8

调优建议

# 默认配置(推荐)
# 自动根据CPU核心数调整

# 手动配置(特殊场景)
-XX:ParallelGCThreads=4  # CPU核心数较少时

# 容器环境(Docker/K8s)
# 注意:需要根据容器CPU限制调整
-XX:ParallelGCThreads=2  # 容器分配2核

3.2 并发GC线程数

# CMS/G1并发标记线程数
-XX:ConcGCThreads=2

# 计算公式
ConcGCThreads = (ParallelGCThreads + 3) / 4

四、ForkJoinPool相关参数

4.1 ForkJoinPool并行度

# 设置ForkJoinPool.commonPool()的并行度
-Djava.util.concurrent.ForkJoinPool.common.parallelism=8

# 默认值:CPU核心数 - 1

代码配置

// 方式1:系统属性(启动时)
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "8");

// 方式2:自定义ForkJoinPool
ForkJoinPool customPool = new ForkJoinPool(8);
customPool.invoke(task);

// 方式3:使用commonPool(不推荐)
ForkJoinPool.commonPool().invoke(task);

五、线程优先级与调度

5.1 线程优先级

# JVM不直接提供参数,通过代码设置
Thread.setPriority(Thread.MAX_PRIORITY);  // 10
Thread.setPriority(Thread.NORM_PRIORITY); // 5(默认)
Thread.setPriority(Thread.MIN_PRIORITY);  // 1

注意

  • ❌ 线程优先级不可靠(依赖操作系统)
  • ❌ 不同操作系统映射不同
  • ✅ 仅作参考,不要依赖

六、实战调优案例

6.1 高并发Web应用

# 场景:高并发API服务
# QPS:10000
# 平均响应时间:50ms

# JVM参数配置
-Xms4g -Xmx4g              # 堆内存4GB
-Xss1m                      # 线程栈1MB
-XX:+UseBiasedLocking       # 启用偏向锁(低竞争)
-XX:ParallelGCThreads=8     # 并行GC线程(8核)
-XX:ConcGCThreads=2         # 并发GC线程
-Djava.util.concurrent.ForkJoinPool.common.parallelism=8

6.2 计算密集型任务

# 场景:大数据处理
# 任务:CPU密集型

# JVM参数配置
-Xms8g -Xmx8g               # 堆内存8GB
-Xss512k                    # 线程栈512KB(减少内存占用)
-XX:-UseBiasedLocking       # 禁用偏向锁(高竞争)
-XX:ParallelGCThreads=16    # 并行GC线程(16核)
-Djava.util.concurrent.ForkJoinPool.common.parallelism=16

6.3 容器环境(Docker/K8s)

# 场景:Docker容器
# 容器限制:2核4GB内存

# JVM参数配置
-Xms2g -Xmx2g               # 堆内存2GB(留2GB给操作系统)
-Xss1m                      # 线程栈1MB
-XX:ParallelGCThreads=2     # 并行GC线程(2核)
-XX:ConcGCThreads=1         # 并发GC线程
-XX:ActiveProcessorCount=2  # 显式指定CPU核心数
-Djava.util.concurrent.ForkJoinPool.common.parallelism=2

注意

  • JVM默认读取宿主机CPU核心数,而非容器限制
  • 使用 -XX:ActiveProcessorCount 显式指定
  • JDK 8u191+、JDK 10+ 支持容器感知

七、监控与排查

7.1 查看JVM参数

# 1. jinfo查看运行时参数
jinfo -flags <pid>

# 2. jcmd查看所有参数
jcmd <pid> VM.flags

# 3. 启动时打印参数
-XX:+PrintFlagsFinal

7.2 线程相关监控

# 1. 查看线程数
jstack <pid> | grep "java.lang.Thread.State" | wc -l

# 2. 查看线程详情
jstack <pid> > threads.txt

# 3. 查看GC线程
jstat -gcutil <pid> 1000

八、核心参数总结

参数默认值推荐值说明
-Xss1MB1MB线程栈大小
-XX:+UseBiasedLocking启用低竞争启用偏向锁
-XX:ParallelGCThreadsCPU核心数CPU核心数并行GC线程
-XX:ConcGCThreads(ParallelGCThreads+3)/4自动并发GC线程
-Djava.util.concurrent.ForkJoinPool.common.parallelismCPU核心数-1CPU核心数ForkJoinPool并行度

总结

JVM线程相关参数是优化并发性能的关键:

核心参数

  • -Xss:控制线程栈大小,影响可创建线程数
  • -XX:+UseBiasedLocking:偏向锁,低竞争场景优化
  • -XX:ParallelGCThreads:并行GC线程数,影响GC性能

调优原则

  1. 线程栈:平衡内存和线程数
  2. 偏向锁:根据竞争程度选择
  3. GC线程:根据CPU核心数调整
  4. 容器环境:显式指定CPU核心数

实战建议

  1. 默认配置:大多数场景无需修改
  2. 压测验证:调优后务必压测
  3. 监控指标:持续监控线程数和GC性能

下一篇预告:我们将深入并发问题排查工具,学习如何快速定位并发问题!