Java并发性能优化关键在于合理管理线程:控制数量防内存与上下文切换开销,用线程池复用;按CPU/IO密集型设大小;慎用ThreadLocal并remove;减少锁竞争与伪共享;禁用Executors工厂方法,显式配置有界线程池并隔离业务域。

Java并发编程能提升系统吞吐量,但线程滥用会显著拖慢性能——关键不在“用不用多线程”,而在于“怎么管好线程”。线程不是免费的,每个线程都占用内存、触发上下文切换、增加GC压力,甚至引发锁竞争和资源争抢。
线程创建与栈内存开销
每个Java线程默认分配1MB(64位JVM,可通过-Xss调整)虚拟机栈空间。哪怕线程刚启动还没执行任务,这部分内存就已预留。1000个空闲线程 ≈ 1GB内存占用,且无法被GC回收。频繁创建/销毁线程(如每请求起一个新线程)还会触发大量对象分配和清理,加重Young GC频率。
- 避免手动new Thread(),改用线程池复用线程
- 根据业务类型合理设置线程池大小:CPU密集型建议core = CPU核数 + 1;IO密集型可适当放大(如2×CPU),但需压测验证
- 使用ThreadLocal时务必调用remove(),防止在线程复用场景下造成内存泄漏
上下文切换的隐性成本
当线程数远超CPU核心数,操作系统需不断保存/恢复寄存器、缓存状态、TLB等,单次切换耗时通常在几十到几百纳秒。高并发下每秒数万次切换会直接吃掉可观的CPU时间,表现为CPU利用率高但有效吞吐低。
- 监控指标:Linux中查看vmstat 1的cs(context switch)列,持续高于10k/s需警惕
- 减少切换的方法:降低线程总数、用异步非阻塞(如Netty、CompletableFuture)替代同步等待、避免无意义的Thread.sleep()或wait()
- 锁粒度越粗、阻塞越久,越容易引发调度器强制切出线程——优先用java.util.concurrent中的无锁结构(如ConcurrentHashMap、LongAdder)
锁竞争与伪共享(False Sharing)
多个线程频繁读写同一缓存行(通常是64字节)的不同变量,会导致CPU缓存频繁失效并同步,性能下降可达数倍。典型场景包括高并发计数器、环形缓冲区的头尾指针、以及未做填充的共享对象字段。
立即学习“Java免费学习笔记(深入)”;
- 用@Contended(需开启-XX:+UseContended)隔离热点字段
- 手动添加long填充字段(如private long p1,p2,p3,p4,p5,p6,p7;)使关键字段独占缓存行
- 避免在循环中反复获取同一把锁;考虑分段锁(如ConcurrentHashMap)、读写锁(ReentrantReadWriteLock)或CAS乐观策略
线程池配置不当引发的雪崩
常见误配:使用Executors.newCachedThreadPool()(无界线程数)、newFixedThreadPool(n)(无界队列)——前者导致OOM,后者让任务无限积压,响应延迟飙升,最终拖垮整个服务。
- 生产环境推荐new ThreadPoolExecutor()显式构造,明确设定corePoolSize、maxPoolSize、workQueue(建议有界队列,如ArrayBlockingQueue)和拒绝策略(如CallerRunsPolicy或自定义降级逻辑)
- 线程池应按业务域隔离(如DB线程池、RPC线程池、定时任务线程池),避免相互干扰
- 通过Micrometer或Actuator暴露线程池指标(activeCount、queueSize、completedTaskCount),结合告警及时发现堆积











