一、书籍定位与主旨
Venkat Subramaniam 在《Programming Concurrency on the JVM》中提出:
“并发不是语法糖,而是思维方式。”
全书围绕“如何在 JVM 上安全、高效、可维护地做并发”展开,给出三条主线:
- 现代 JDK 并发工具(java.util.concurrent)
- 软件事务内存(STM)
- 演员模型(Actor)
作者强调:共享可变状态是万恶之源;隔离可变或不可变才是正道。书中用大量可运行示例(Java / Scala / Groovy / JRuby / Clojure)演示三种模型如何落地,并对比性能、可读性、调试成本。
二、内容分层速览
Part I 策略与思维(第1-3章)
- 并发价值:榨干多核、降低延迟、提升吞吐
- 并发陷阱:可见性、竞态、死锁、饥饿
- 设计取舍:共享可变 vs 隔离可变 vs 纯不可变
- 分治公式:线程数 ≈ CPU核 / (1 – 阻塞系数)
- 负载划分:IO 密集用“超多线程”,计算密集用“核数线程”+“超多任务片”
Part II 现代 JDK 并发(第4-5章)
- ExecutorService、ForkJoinPool、CountDownLatch、CyclicBarrier、CompletableFuture 用法与坑点
- ConcurrentHashMap、BlockingQueue、CopyOnWriteArrayList 等可扩展集合为何比 synchronized 集合快
- ReentrantLock、ReadWriteLock、StampedLock 相对 synchronized 的优势:可限时、可中断、可公平、可多条件
- 共享可变代码重构六步曲:
- 禁止构造函数里启动线程
- 用线程池代替裸 Thread
- 保证跨内存屏障(volatile / synchronized / final)
- 缩小锁粒度(字段级、分段锁、原子变量)
- 复合操作加锁或 CAS
- 用不可变消息传递替代共享可变
Part III 软件事务内存(第6-7章)
- STM 核心:把“锁”上升为“事务”,让运行时自动处理冲突、重试、可见性
- Clojure 示范:ref / dosync / alter / commute / ensure;写偏(write skew)与解决办法
- Akka-STM(基于 Multiverse)在 Java/Scala 中的 API:
- Atomic<T> + atomically()
- 嵌套事务、只读事务、阻塞重试 retry()
- 提交钩子 deferred()、回滚钩子 compensating()
- STM 适用场景:读多写少、冲突概率低;高冲突写场景会退化为“不断重试”
Part IV 演员模型(第8-9章)
- Actor = 单线程 + 邮箱 + 不可变消息;多个 Actor 共享线程池,顺序处理邮箱,天然无锁
- Akka 基础:UntypedActor(Java)/ Actor trait(Scala);!、!!、!!! 三种消息发送语义
- 案例:多线程统计素数、递归遍历目录大小——Actor 版代码量下降 30-50%,性能持平
- Typed Actor:接口+实现,方法调用即消息;适合既想保留 OO 语义又要并发安全的场景
- 内部定时任务(murmurs):用 Scheduler 发消息给自身,避免外部线程碰状态
- 远程 Actor:Netty + Protobuf,透明跨进程发消息
- 协调一致性:
- Transactor(STM + Actor):coordinate() 把多个 Actor 拉进同一事务,成功一起提交,失败一起回滚
- Coordinating Typed Actor:@Coordinated 注解 + coordinate{…} 代码块,实现跨账户转账原子性
Part V 多语言实战(第9章)
- Groovy:GPars 提供 DefaultActor / actor{} 闭包;与 Java 互操作无门槛
- JRuby:直接 import Clojure STM 或 Akka;注意 NativeException 包装需手动 unwrap
- Scala:既可用 Akka 原生 API,也可直接用 Clojure STM 的 Ref 与 LockingTransaction
- 结论:并发模型与语言正交;遵循“值不可变、事务幂等、消息不可变”三原则即可
三、特色与价值
- 一书三模型:把 JDK、STM、Actor 放在同一坐标系对比,帮助读者根据“冲突概率、吞吐需求、代码复杂度”做选型
- 多语言对照:同一示例用 Java/Scala/Groovy/JRuby/Clojure 五种语法实现,方便团队跨语言落地
- 性能数据翔实:作者在同一台双核/八核机器跑基准测试,给出线程数-分片数-耗时曲线,避免“拍脑袋”调优
- 重构步骤清晰:共享可变代码 → 加锁 → 缩小锁 → 原子变量 → 不可变消息 → Actor/STM,层层递进,老代码改造不再无从下手
- 坑点与边界直言不讳:STM 高写冲突会退化为重试风暴;Actor 可能死锁或饿死;远程 Actor 需关注序列化——提前帮读者踩坑
四、适合读者
- 拥有 1 年以上 JVM 经验,却被“并发 bug 难重现、难调试”折磨的工程师
- 需要维护老系统 synchronized 代码,想逐步迁移到现代并发模型的架构师
- 对函数式、不可变、Actor、STM 感兴趣,却苦于“概念懂、落地难”的开发者
- 技术团队负责人想在 Java/Kotlin/Scala/Groovy 多语言栈中统一并发规范
五、阅读建议
- 先通读 Part I 建立“并发思维”,再挑自己最急需的模型深入
- 每章示例代码均可直接运行,建议:
- 把线程数、分片数、超时参数当变量,亲眼看“性能曲线”
- 故意制造高冲突(多线程写同一 ref / 同一账户),观察 STM 重试、Actor 邮箱堆积
- 老项目改造:
- 第 5 章“共享可变六步曲”当 checklist,逐条对照现有代码
- 新模块优先用 Actor(隔离可变)或 STM(读多写少),老模块逐步“边缘推进”
- 多语言混合:本书示例均可互操作,团队可保留各自语言习惯,又共享同一并发模型
六、总结
《Programming Concurrency on the JVM》用“共享不可变、隔离可变、事务自动重试、演员顺序处理”四大法宝,带你逃离 synchronized 的暗坑,在多核时代写出“快且稳”的 JVM 并发代码。