一、线程栈相关参数
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
八、核心参数总结
| 参数 | 默认值 | 推荐值 | 说明 |
|---|---|---|---|
| -Xss | 1MB | 1MB | 线程栈大小 |
| -XX:+UseBiasedLocking | 启用 | 低竞争启用 | 偏向锁 |
| -XX:ParallelGCThreads | CPU核心数 | CPU核心数 | 并行GC线程 |
| -XX:ConcGCThreads | (ParallelGCThreads+3)/4 | 自动 | 并发GC线程 |
| -Djava.util.concurrent.ForkJoinPool.common.parallelism | CPU核心数-1 | CPU核心数 | ForkJoinPool并行度 |
总结
JVM线程相关参数是优化并发性能的关键:
核心参数:
- ✅ -Xss:控制线程栈大小,影响可创建线程数
- ✅ -XX:+UseBiasedLocking:偏向锁,低竞争场景优化
- ✅ -XX:ParallelGCThreads:并行GC线程数,影响GC性能
调优原则:
- 线程栈:平衡内存和线程数
- 偏向锁:根据竞争程度选择
- GC线程:根据CPU核心数调整
- 容器环境:显式指定CPU核心数
实战建议:
- 默认配置:大多数场景无需修改
- 压测验证:调优后务必压测
- 监控指标:持续监控线程数和GC性能
下一篇预告:我们将深入并发问题排查工具,学习如何快速定位并发问题!