支撑单机十万级qps需科学配置线程池:io密集型设corepoolsize为cpu核数×2~3,cpu密集型设为核数+1,maxpoolsize≤核数×4;用有界arrayblockingqueue(如10000),禁用无界队列;拒绝策略按业务分级,关键路径用callerrunspolicy;禁用executors,手动构建线程池并集成监控。

要支撑单机十万级QPS,线程池不能靠堆线程数硬扛——10万QPS × 100ms耗时 = 理论需1万个活跃线程,但JVM在千级线程时就已面临上下文切换爆炸、内存溢出风险。真正有效的优化,是让更少的线程干更多的活,同时守住系统不雪崩的底线。
按任务类型精准计算线程数
盲目设 corePoolSize=200 或 500 是无效的。必须先判断任务性质:
- 若任务以数据库查询、HTTP调用、消息发送为主(IO密集型),核心线程数建议设为 CPU核心数 × 2~3;例如16核机器,取32~48;
- 若含大量加解密、规则引擎计算等(CPU密集型),核心线程数控制在 CPU核心数 + 1 即可,如16核配17;
- 最大线程数不宜超过 CPU核心数 × 4,避免争抢资源;对16核机器,max=64较稳妥;
- keepAliveTime 设为60秒,确保突发流量退去后非核心线程能及时回收。
选用有界队列并严控容量
LinkedBlockingQueue无界队列是高并发系统的“定时炸弹”——请求持续涌入会无限堆积,迅速吃光堆内存。必须改用有界队列:
- 推荐 ArrayBlockingQueue,显式指定容量(如10000),从源头限制积压上限;
- 队列大小不是越大越好:设为 核心线程数 × 平均任务处理时间(秒)× 预期峰值QPS缓冲系数;例如32线程、100ms任务、缓冲1.5倍,则 ≈ 32 × 10 × 1.5 = 480 → 实际取1000~5000更合理;
- 切忌用 SynchronousQueue,它零缓冲,全靠线程即时消费,无抗抖动能力,仅适合毫秒级纯内存计算场景。
拒绝策略必须业务友好
默认的 AbortPolicy 直接抛异常,等于把压力甩给上游,极易引发级联失败。应按业务重要性分级处理:
- 对通知、日志、埋点等非核心任务,用 DiscardPolicy 或 DiscardOldestPolicy,丢弃最老/最新任务保主干通路;
- 对支付回调、库存扣减等关键路径,优先选 CallerRunsPolicy:由调用方线程自己执行,天然限流,且不丢失任务;
- 进阶做法是自定义拒绝策略,将被拒任务写入 Kafka 备用队列,由降级消费者异步重试或人工干预。
配套必须做三件事
光调参数不够,还需工程化保障:
- 禁用 Executors 工具类:它隐藏参数、无法监控、线程名混乱,一律用 ThreadPoolExecutor 手动构建;
- 注入自定义 ThreadFactory:统一命名线程(如 “task-pool-%d”),便于排查线程阻塞、泄露;
- 集成 Actuator + Prometheus:暴露 activeCount、queueSize、completedTaskCount 等指标,设置告警阈值(如 queueSize > 80% 容量立即预警)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











