README
# 第 3 卷|并发之道
专栏分量最重的一卷——18 篇文章,从硬件原子指令到结构化并发,把并发编程半个世纪的进化史完整走一遍。
# 🎯 这一卷要回答什么
并发是程序员永恒的痛点。你也许写过 synchronized、AtomicInteger、async/await、channel,但能回答下面这些"为什么"吗?
- 线程到底是软件概念还是硬件概念? 没有 OS 之前世界上有没有"线程"?
- 共享内存和消息传递——为什么 Erlang 选了一条路、Java 选了另一条?两条路真的不能合并吗?
- 为什么并发 Bug 可以归纳成只有三种(可见性 / 原子性 / 有序性)?
- CAS 解决了什么矛盾? 为什么硬件层面有了 LOCK#,软件层面还需要循环 CAS?
- 协程是 1958 年发明的,为什么 2018 年才在 Kotlin / Swift / Java 21 集中爆发?
- 结构化并发——为什么 Nathaniel Smith 说"goroutine 跟 goto 一样有害"?
这一卷不只是教你"用哪个 API",而是带你看见:每一个并发原语都是某个具体矛盾在某个历史时间点的最优解。
# 📖 篇章总览(18 篇)
# 🌱 起源篇(5 篇):理解线程为何而生
| 序号 | 文档 | 核心矛盾 |
|---|---|---|
| 3.1 | 线程前世今生探索 | 进程不够用?1:1 / N:1 / M:N 模型如何演进 |
| 3.2 | 并发上下文切换原理 | 进程 / 线程 / 协程切换代价的根本差异 |
| 3.3 | 线程通信设计思想 | 共享内存 vs 消息传递 —— 两条路线的硬件根因 |
| 3.4 | 线程异常设计原理 | 异常从硬件中断到语言层面经历了什么 |
| 3.5 | 多线程并发经典案例 | 售票问题:3 行代码引出 3 类 Bug |
# 🔥 矛盾篇(5 篇):理解并发 Bug 的根源与解法
| 序号 | 文档 | 核心矛盾 |
|---|---|---|
| 3.6 | 并发 Bug 源头由来 | 可见性 / 原子性 / 有序性 —— 三种 Bug 的硬件根因 |
| 3.7 | 并发编程设计思想 | 分工 → 同步 → 互斥,并发的三大命题 |
| 3.8 | 并发编程安全设计 | 不可变 / TLS / 读写分离 / 无锁 —— 四种避坑策略 |
| 3.9 | 锁核心设计和思想 | 从 LOCK# 指令到 Java 锁升级的完整链路 |
| 3.10 | 理解 CAS 设计由来 | 从哲学到硬件,CAS 的 ABA 与解法 |
# 🚀 范式篇(4 篇):理解现代并发模型
| 序号 | 文档 | 核心矛盾 |
|---|---|---|
| 3.11 | 异步和同步的设计 | 同步 → 多线程 → 回调 → async/await 的演进 |
| 3.12 | 单线程模型的思想 | 单线程为何反而能高并发? |
| 3.13 | 协程核心设计思想 | "挂起 / 恢复" 的机器本质;有栈 vs 无栈 |
| 3.14 | Actor 与 CSP 并发模型 | Erlang 的 Actor vs Go channel 的 CSP |
# 🏊 池化与结构化篇(4 篇):把前面所有原理用起来
| 序号 | 文档 | 核心矛盾 |
|---|---|---|
| 3.15 | 线程池的设计思想 | 池化思想的本质:生产者 - 消费者 |
| 3.16 | 线程池设计核心原理 | ctl 变量、状态机、Worker 模型 |
| 3.17 | 线程池使用技巧 | 7 大参数调优实战 |
| 3.18 | 结构化并发设计思想 | Kotlin / Swift / Java 21 / Trio 让并发"回归大括号" |
# 🔗 知识脉络
flowchart TB
A[3.1-3.5 起源篇<br/>线程为何被发明] --> B[3.6-3.10 矛盾篇<br/>并发 Bug 的根源与解法]
B --> C[3.11-3.14 范式篇<br/>现代并发模型]
C --> D[3.15-3.18 池化与结构化<br/>实战集大成]
D --> F[读完此卷<br/>你能在脑中演进半世纪并发史]
style F fill:#d4edda
1
2
3
4
5
6
2
3
4
5
6
# 🌉 与其他卷的承接
- 承接第 2 卷:第 2 卷讲对象布局与调用栈,本卷的"锁升级"恰恰是 mark word 的几个 bit 在做状态机;协程"自己的栈"也是对栈帧的延伸。
- 通往第 4 卷:内存模型(JMM / C++ MM)是并发原语正确性的基础,将在第 4 卷以"内存"视角重新审视。
- 通往第 5 卷:第 5 卷"消息机制"本质就是单线程模型 + 事件循环 + 无锁队列。
# 💡 学完你能回答
- 为什么
volatile不能保证原子性,但能保证可见性?硬件上是怎么实现的? synchronized的偏向锁、轻量级锁、重量级锁,性能差距究竟有多少?什么场景该选哪个?- async/await 不就是回调的语法糖吗?JVM 字节码层面有什么不同?
- 为什么 Go 不需要线程池?Goroutine 调度的 GMP 模型究竟解决了什么矛盾?
- 线程池 corePoolSize、maximumPoolSize、queueCapacity 三者的"死亡组合"是什么?
# ⚠️ 学习节奏建议
这卷信息密度极高,强烈不建议三天打鱼。推荐:
第 1 周:3.1-3.5(起源篇) 循序渐进
第 2 周:3.6-3.10(矛盾篇) 硬核硬啃
第 3 周:3.11-3.14(现代范式) 深入新世界
第 4 周:3.15-3.18(池化 + 结构化) 落地总结
1
2
3
4
2
3
4
并发是个只能靠理解、不能靠记忆的领域。当你能在脑子里画出"一行代码触发的所有内存屏障 / cache 同步 / OS 调度"时,这一卷才算真正读完。
上次更新: 2026/06/07, 10:26:12