多核cpu需任务调度与缓存对齐:cpu密集型线程数=核心数,io密集型≈2×核心数+1;用completablefuture+自定义forkjoinpool、异步io、cpu绑定提升性能;volatile/synchronized/locksupport配合屏障保障可见性;优先无锁结构、分段锁、避免锁内io;jvm层协同调优g1gc、jit、jfr、tlab等。

紧扣硬件特性设置线程与任务模型
多核 CPU 不是简单叠加算力,而是要求任务调度与缓存层次严格对齐。CPU 密集型任务线程数宜设为 CPU 核心数,IO 密集型则可设为 2×核心数 + 1,避免线程过多引发频繁上下文切换。任务本身需支持自然拆分——例如将批量订单处理按用户 ID 分片,每个子任务无共享状态,直接交由线程池并行执行。
推荐做法包括:
- 使用 CompletableFuture.supplyAsync() 配合自定义 ForkJoinPool 控制并行度
- 对长耗时 IO 操作(如远程调用、DB 查询)启用异步非阻塞方式(Netty/NIO),释放线程资源
- 关键计算线程绑定到固定 CPU core(通过 Thread.setAffinity 或 JNI 调用 sched_setaffinity),减少缓存迁移开销
用内存屏障守住可见性与有序性底线
Java 不暴露底层屏障指令,但通过语言机制隐式插入。真正起效的不是“加屏障”,而是“选对语义载体”:
-
volatile:适用于单变量写后读场景(如开关标志、状态位),它在写操作后插入
StoreStore+StoreLoad,读操作前插入LoadLoad+LoadStore,成本低且不可重排序 -
synchronized:出入临界区自动触发
StoreLoad,保证锁内所有修改对后续获取该锁的线程可见;适合多变量协同更新(如账户余额+流水号) -
LockSupport.park/unpark + CAS:在无锁队列、RingBuffer 等高性能结构中,配合
Unsafe.putOrderedXXX()和Unsafe.fullFence()实现细粒度控制
切忌滥用 volatile 修饰对象引用再反复 new 新实例——这会绕过屏障语义,导致旧引用残留或构造未完成就发布。
锁优化要从竞争源头分级治理
锁不是越少越好,而是越“准”越好。现代 JVM 的锁升级机制(偏向→轻量→重量)已大幅降低开销,但设计上仍需主动规避热点:
- 优先用无锁结构:计数用
LongAdder(分段累加)、集合用ConcurrentHashMap(JDK8 后取消 Segment,改用synchronized+ CAS 控制桶级锁) - 锁粒度下沉:不要锁整个 Map,改用
computeIfAbsent(key, k -> new ReentrantLock())按 key 分段加锁;对数组类结构,可用@Contended注解隔离伪共享字段 - 避免锁内做 IO 或长耗时操作:把日志记录、远程调用等移出同步块,必要时用生产者-消费者模式解耦
实测表明,在 32 核服务器上,将一个全局计数器从 AtomicLong 升级为 LongAdder,QPS 提升约 3.2 倍;将单锁订单服务改为按商户 ID 分片锁后,P99 延迟下降 67%。
结合 JVM 层与代码层做协同调优
脱离运行时环境谈并发优化等于纸上谈兵。几个关键协同点:
- 开启
-XX:+UseG1GC并设置-XX:MaxGCPauseMillis=50,G1 对大堆和并发标记更友好;避免 CMS 已废弃带来的兼容风险 - 使用
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly查看热点方法是否被 JIT 编译,确认synchronized是否已优化为轻量锁或锁消除 - 通过 JFR(Java Flight Recorder)采集
jdk.ThreadPark、jdk.JavaMonitorEnter事件,定位真实锁竞争点,而非凭经验猜测 - 对高频短生命周期对象,启用
-XX:+UseTLAB(默认开启)并调大-XX:TLABSize,减少 Eden 区同步分配开销
一次电商秒杀压测中,仅调整 -XX:ReservedCodeCacheSize=512m 和关闭 -XX:-UseBiasedLocking(因高竞争下偏向锁撤销代价高),就使吞吐提升 18%,且 GC 时间稳定在 3ms 内。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











