“系统性”学习高并发路线
一、为什么需要“系统性”学习高并发?
很多工程师陷入以下误区:
- ❌ 只会背“Redis 缓存穿透怎么解决”,但不知道什么时候该用布隆过滤器 vs 空值缓存
- ❌ 知道
synchronized和ReentrantLock区别,但线上出现线程阻塞却不会分析 - ❌ 能说出“分库分表”,但不清楚什么时候该分、怎么分、如何保证全局 ID 唯一
✅ 真正的高并发能力 = 理解原理 + 能诊断问题 + 能设计方案 + 能压测验证
二、高并发知识体系全景图(细化版)
我们将整个体系拆解为 5 大核心层 + 2 条贯穿线:
┌───────────────────────────────────────┐
│ 5. 分布式架构与高可用设计 │ ← 系统级:容灾、扩展、治理
├───────────────────────────────────────┤
│ 4. 中间件与数据层优化 │ ← 支撑层:缓存、MQ、DB、限流
├───────────────────────────────────────┤
│ 3. JVM 与运行时性能调优 │ ← 运行时:GC、内存、线程
├───────────────────────────────────────┤
│ 2. Java 并发编程模型 │ ← 编码层:锁、线程池、原子操作
├───────────────────────────────────────┤
│ 1. 计算机系统基础 │ ← 底层:CPU、内存、IO、网络
└───────────────────────────────────────┘↑ ↑【贯穿线1:可观测性】 【贯穿线2:压测与验证】(监控/日志/链路追踪) (JMeter/wrk/全链路压测)三、逐层详解:学什么?怎么学?做什么实验?
第 1 层:计算机系统基础(夯实根基)
核心目标:
理解程序在操作系统和硬件层面如何运行,明白并发瓶颈的物理根源。
关键知识点:
| 主题 | 必须掌握的内容 |
|---|---|
| CPU 与缓存 | - CPU 多核并行 vs 并发 - 缓存行(Cache Line)大小(通常 64B) - 伪共享(False Sharing)现象及避免(@Contended 注解) |
| 内存模型 | - 主内存 vs 工作内存 - 内存屏障(Memory Barrier)作用 - happens-before 规则(8 条) |
| 上下文切换 | - 线程切换开销(寄存器保存/恢复) - 如何用 vmstat 或 pidstat 查看上下文切换次数 |
| I/O 模型 | - BIO / NIO / AIO 区别 - Reactor 模式(单 Reactor / 主从 Reactor) - epoll 为什么比 select 高效? |
| 网络协议 | - TCP 拥塞控制(慢启动、快重传) - TIME_WAIT 状态影响 - HTTP/1.1 vs HTTP/2 多路复用 |
动手实验:
- 观察伪共享:写两个相邻的 volatile 变量,多线程修改,对比加
@sun.misc.Contended前后的性能差异(用 JMH) - 模拟上下文切换:创建 10000 个线程执行空循环,用
top -H -p <pid>查看线程数和 CPU 切换开销 - 抓包分析 TCP:用
tcpdump抓取 HTTP 请求,观察三次握手和四次挥手过程
推荐资源:
- 书籍:《深入理解计算机系统》(CSAPP)第 6、9、11 章
- 视频:MIT 6.S081 Operating System Engineering(免费公开课)
- 工具:
perf,strace,lsof,netstat
第 2 层:Java 并发编程模型(编码核心)
核心目标:
写出线程安全、高性能、无死锁的并发代码。
关键知识点:
| 模块 | 必须掌握的内容 |
|---|---|
| synchronized | - 对象头 Mark Word 结构 - 偏向锁 → 轻量级锁 → 重量级锁升级过程 - 锁消除、锁粗化 JIT 优化 |
| volatile | - 禁止指令重排序 + 保证可见性 - 不能保证原子性(i++ 问题) - DCL 单例中为何需要 volatile? |
| JUC 工具类 | - ReentrantLock 公平锁 vs 非公平锁- Condition 实现生产者消费者- CountDownLatch vs CyclicBarrier 使用场景 |
| 线程池 | - ThreadPoolExecutor 7 个参数含义- 拒绝策略(AbortPolicy / CallerRunsPolicy) - 如何合理设置 corePoolSize?(CPU 密集 vs IO 密集) |
| 并发集合 | - ConcurrentHashMap 1.8 分段锁 → CAS + synchronized- CopyOnWriteArrayList 适用场景(读多写少)- BlockingQueue 类型对比(ArrayBlockingQueue vs LinkedBlockingQueue) |
| AQS | - state 状态 + CLH 队列 - acquire / release 流程 - 自定义同步器(如实现一个简易信号量) |
动手实验:
- 手写线程安全单例:DCL + volatile,用 JUnit 多线程测试是否唯一
- 模拟线程池拒绝:创建固定线程池,提交大量任务,观察
RejectedExecutionException - 对比 HashMap vs ConcurrentHashMap 性能:用 JMH 压测 100 线程并发 put/get
推荐资源:
- 书籍:《Java 并发编程实战》(Brian Goetz)—— 圣经级
- 源码:阅读
ReentrantLock,ThreadPoolExecutor,ConcurrentHashMap源码 - 工具:JMH(Java Microbenchmark Harness)做微基准测试
第 3 层:JVM 与运行时调优(性能保障)
核心目标:
让应用在高并发下不 OOM、不 Full GC、线程不堆积。
关键知识点:
| 主题 | 必须掌握的内容 |
|---|---|
| 内存结构 | - 堆(新生代 Eden/S0/S1 + 老年代) - 方法区(元空间替代永久代) - 虚拟机栈 vs 本地方法栈 |
| GC 算法 | - 标记-清除 / 复制 / 标记-整理 - G1 的 Region 设计 + Remembered Set - ZGC 的着色指针 + Load Barrier |
| GC 调优 | - -Xms / -Xmx 设置建议(设为相同值)- 新生代大小对 YGC 频率的影响 - 如何通过 GC 日志分析问题(UseGCLogFileRotation) |
| 线程分析 | - jstack 查看线程状态(RUNNABLE / BLOCKED / WAITING)- 死锁检测(Found one Java-level deadlock) - 线程池任务堆积排查 |
| 内存泄漏 | - 静态集合持有对象引用 - ThreadLocal 未 remove - 用 MAT 分析 Dominator Tree |
动手实验:
- 制造内存泄漏:静态 Map 不断 put 对象,观察 heap 增长,用 MAT 分析
- 模拟 Full GC:创建大对象直接进入老年代,触发 Full GC,用
-XX:+PrintGCDetails查看日志 - 线程死锁复现:两个线程交叉获取锁,用
jstack检测死锁
推荐工具:
jstat -gcutil <pid> 1000:实时看 GC 情况jmap -histo:live <pid>:查看对象分布- Arthas:线上诊断神器(
thread,watch,trace命令)
第 4 层:中间件与数据层优化(流量承载)
核心目标:
通过缓存、异步、分片、限流四大手段扛住高并发。
模块详解:
4.1 Redis(缓存核心)
- 三大问题:
- 穿透:查询不存在的数据 → 布隆过滤器 or 空值缓存(注意过期时间)
- 击穿:热点 key 过期瞬间大量请求 → 互斥锁(setnx) or 逻辑过期
- 雪崩:大量 key 同时过期 → 随机过期时间 + 多级缓存
- 集群方案:
- 主从复制 + 哨兵(Sentinel)→ 高可用
- Redis Cluster(16384 slots)→ 自动分片
- 性能优化:
- Pipeline 批量操作
- 避免大 Key(string > 10KB, list > 5000 元素)
- 使用 Hash Tag 保证多字段操作在同一个 slot
✅ 实验:用 Spring Boot + Redis 实现一个防重提交注解(基于 token + setnx)
4.2 消息队列(异步解耦)
- 选型对比:
MQ 优势 适用场景 Kafka 高吞吐、持久化 日志、埋点、流处理 RocketMQ 事务消息、延迟消息 订单、支付 RabbitMQ 可靠性、管理界面 企业内部系统 - 关键问题:
- 如何保证消息不丢失?(生产端 confirm + 存储持久化 + 消费端 ack)
- 如何避免重复消费?(幂等设计:数据库唯一索引 / Redis token)
- 消息积压怎么办?(临时扩容消费者 + 跳过非核心消息)
✅ 实验:用 RocketMQ 实现订单创建后异步发送短信 + 更新积分
4.3 数据库优化
- 连接池:HikariCP(默认)参数调优(maximumPoolSize ≈ (core_count * 2) + effective_spindle_count)
- 读写分离:ShardingSphere-JDBC 配置主从
- 分库分表:
- 水平分片:按 user_id 取模
- 全局 ID:雪花算法(Snowflake) or Leaf(美团)
- 跨分片查询:避免 or 用 ES 同步
✅ 实验:用 ShardingSphere 实现订单表按 user_id 分 4 库 4 表
4.4 限流熔断
- 限流算法:
- 计数器(简单但临界问题)
- 滑动窗口(Sentinel 默认)
- 令牌桶(Guava RateLimiter)
- 漏桶(适用于匀速处理)
- Sentinel 实战:
- QPS 流控
- 熔断降级(慢调用比例)
- 系统自适应保护(Load / CPU)
✅ 实验:为商品详情接口添加 Sentinel 限流,QPS > 100 时返回降级页面
第 5 层:分布式架构与高可用设计(系统级)
核心目标:
构建可扩展、可容错、可监控的高并发系统。
关键架构模式:
| 模式 | 说明 | 工具 |
|---|---|---|
| 无状态服务 | 便于水平扩展,Session 外置到 Redis | Spring Session |
| 多级缓存 | 浏览器缓存 → CDN → Nginx → 本地缓存 → Redis → DB | Caffeine + Redis |
| 异步化 | 核心链路同步,非核心走 MQ | RocketMQ |
| 服务治理 | 注册发现、负载均衡、配置中心 | Nacos |
| 链路追踪 | 定位慢接口、依赖关系 | SkyWalking |
| 多活架构 | 单元化部署,故障隔离 | 阿里 LDC 架构 |
经典案例:秒杀系统设计
- 前端:按钮置灰 + 验证码(防刷)
- 网关层:Nginx 限流(limit_req)
- 服务层:
- 库存预热到 Redis(Lua 脚本扣减,保证原子性)
- 下单请求进 MQ,异步创建订单
- 本地缓存 + 布隆过滤器防穿透
- 数据层:订单分库分表,库存 DB 最终一致性对账
✅ 项目实战:GitHub 搜索 “seckill-system” 参考开源实现
四、贯穿两条线:可观测性 + 压测验证
1. 可观测性(Observability)
- Metrics:Prometheus + Grafana(QPS、RT、错误率)
- Logging:ELK(Elasticsearch + Logstash + Kibana)
- Tracing:SkyWalking(调用链、拓扑图)
💡 没有监控的高并发系统 = 盲人开车
2. 压测与验证
- 工具:
- JMeter:图形化,适合复杂场景
- wrk:命令行,超高并发(百万级连接)
- ChaosBlade:故障注入(模拟网络延迟、服务宕机)
- 方法:
- 单接口压测 → 链路压测 → 全链路压测
- 逐步加压,观察系统拐点(Knee Point)
✅ 实验:用 wrk 压测你的秒杀接口,观察 Redis CPU、DB 连接数变化
五、推荐学习路径
| 周数 | 主题 | 具体任务 |
|---|---|---|
| 第 1-2 周 | Java 并发基础 | - 精读《Java 并发编程实战》前 8 章 - 手写线程池、DCL 单例 - 用 JMH 做并发性能对比 |
| 第 3-4 周 | JVM 调优 | - 学习 GC 原理 - 模拟 OOM/Full GC - 掌握 jstack/jmap/Arthas |
| 第 5-6 周 | Redis + 缓存 | - 搭建 Redis Cluster - 实现缓存三大问题解决方案 - 集成 Spring Cache |
| 第 7-8 周 | MQ + 数据库 | - RocketMQ 事务消息实战 - ShardingSphere 分库分表 - HikariCP 参数调优 |
| 第 9-10 周 | 限流熔断 + 微服务 | - Sentinel 流控规则配置 - Spring Cloud Alibaba 搭建微服务 - SkyWalking 链路追踪 |
| 第 11-12 周 | 项目整合 + 压测 | - 实现一个高并发秒杀 demo - 全链路压测 + 监控告警 - 撰写技术文档(可作面试作品) |
六、面试高频问题清单(检验学习成果)
synchronized锁升级过程是怎样的?- 线程池 corePoolSize=10, max=20, queue=100,提交 150 个任务会发生什么?
- Redis 缓存雪崩和击穿的区别?如何解决?
- 如何保证 RocketMQ 消息不丢失?
- 分库分表后,如何实现全局唯一 ID?
- 什么是伪共享?如何避免?
- G1 和 CMS 的区别?ZGC 为什么能做到低延迟?
- 秒杀系统如何防止超卖?
七、总结:高并发学习的终极心法
🔑 不要追求“知道所有技术”,而要追求“理解问题本质 + 能设计方案 + 能落地验证”
- 从问题出发:先想“如果线上 QPS 突增 10 倍,我的系统哪里会崩?”
- 动手驱动:每个知识点都配一个 mini 项目或实验
- 闭环验证:学完就压测、就监控、就写文档
- 持续迭代:高并发没有终点,只有不断逼近最优解
