Java 并发编程
并发的本质、内存模型、控制哲学、性能与伸缩性、测试与反模式等原理,见母篇/编程语言/并发编程.html。本文聚焦 Java/JVM 的具体落地与独有机制。
Java 并发实现栈
Java 把母篇所说的"协调机制"落地为一个分层栈,上层依赖下层:
并发设计模式(实例封闭、委托、状态依赖…) ↓JUC 抽象(Lock、Semaphore、CyclicBarrier、CountDownLatch) ↓同步器底座(AQS)+ 等待通知(wait/notify、Condition) ↓硬件(内存屏障、CAS / CompareAndSwap)AQS(AbstractQueuedSynchronizer) 是 JUC 的统一底座:用一个 volatile int state + CLH 等待队列,把"获取 / 释放"抽象为模板方法。ReentrantLock、Semaphore、CountDownLatch 都只是对 state 语义的不同解释。理解 AQS,等于理解半个 JUC。
可见性与有序性的 Java 工具
母篇讲清了 happens-before 的原理;Java 把它落为三个关键字,各自建立不同的 hb 边:
| 关键字 | 建立的保证 | happens-before 规则 |
|---|---|---|
synchronized | 互斥 + 可见性 + 有序性 | 解锁 hb 后续加锁 |
volatile | 可见性 + 有序性(非原子) | 写 hb 后续读 |
final | 安全发布的初始化可见性 | 构造结束 freeze,正确发布后可见 |
完整的 JMM happens-before 规则(程序顺序、线程启动 / 终止、中断等)见 /编程语言/JAVA/JVM/JAVA内存模型.html。
对象共享的 Java 设计模式
母篇的设计模式是通用的(Immutable、Thread Confinement…);Java 实践层有三个更具体的惯用法:
| 模式 | 做法 | 关键约束 |
|---|---|---|
| 实例封闭 | 把非线程安全对象包进受控边界,对外只暴露安全接口 | 并发策略集中在一处,最稳健 |
| 线程安全委托 | 把安全责任交给底层线程安全组件(如 ConcurrentHashMap) | 不得引入跨组件的复合状态——"多个原子操作组合后不再原子" |
| 状态依赖操作 | 操作依赖某状态条件成立 | 条件检查 → 等待 → 唤醒后重校验 |
对象安全发布的手段(静态初始化 / final / volatile / 锁)及其 hb 机制见母篇「安全发布」。
等待-通知与协作机制
等待不是睡眠,而是条件未满足时让出执行权、等待通知。
wait/notify 三原则(违反即 Bug):
- 等待必须在持有锁时进行,`wait()` 会**释放锁**
- 被唤醒 ≠ 条件满足 → 条件检查必须放在 **while 循环**里
- 优先 `notifyAll`,`notify` 易丢唤醒
Condition(显式条件队列) 相比 wait/notify 的增量:多条件分离、精准唤醒、可中断 / 可超时等待。它是状态机式并发设计的基础设施。
取消、中断与生命周期管理
Java 没有"强杀线程"——生命周期管理是一套协作协议:
- **取消是协作而非命令**:被取消方自行决定是否响应、如何清理。
- **中断是协作信号而非异常**:`interrupt()` 只设标志位。设计原则:不知道中断策略就不要中断;阻塞方法要么响应中断,要么明确声明不可中断。
- **Future / Executor**:把线程管理权从业务逻辑剥离,提供统一的提交、取消、超时与生命周期控制。
活跃性的 Java 预防
活跃性失效的原理(死锁 / 活锁 / 饥饿、Coffman 条件)见母篇「进度协调失效」。Java 层的预防手段:
| 问题 | Java 预防手段 |
|---|---|
| 死锁 | 固定全局加锁顺序、tryLock(timeout) 超时放弃、一次性申请、缩小临界区 |
| 活锁 | 随机退避(重试间隔随机化)、限制重试次数、引入协调者 |
| 饥饿 | 公平锁 new ReentrantLock(true)、避免优先级反转、动态优先级提升 |
预防优于检测,设计优于补救。
JVM 锁优化
JVM 对 synchronized 做了一套自动优化,核心是按竞争程度逐级升级,避免无谓的重量级开销:
无锁 → 偏向锁 → 轻量级锁 → 重量级锁 (无竞争) (轻度CAS竞争) (重度竞争挂起)| 优化 | 作用 |
|---|---|
| 偏向锁 | 无竞争时偏向首个线程,省去 CAS(注:JDK 15 起默认废弃,JEP 374) |
| 轻量级锁 | 轻度竞争用 CAS 自旋,不挂起线程 |
| 自旋 / 自适应自旋 | 短暂忙等避免上下文切换;自适应按历史动态调整自旋次数 |
| 锁消除 | JIT 判定不可能竞争(如未逸出的局部对象)直接去锁 |
| 锁粗化 | 把连续的细粒度加锁合并,减少反复加解锁 |
前提:这些优化只能锦上添花,救不了本身不合理的并发设计。
关联内容(自动生成)
- [/编程语言/并发编程.html](/编程语言/并发编程.html) 并发原理母篇——本文是其在 Java/JVM 上的落地实例
- [/编程语言/JAVA/JAVA并发编程/基础概念.html](/编程语言/JAVA/JAVA并发编程/基础概念.html) Java 并发基础概念,包括线程生命周期、并发问题等核心知识点
- [/编程语言/JAVA/JAVA并发编程/线程.html](/编程语言/JAVA/JAVA并发编程/线程.html) Java 中线程的创建、管理与控制机制
- [/编程语言/JAVA/JAVA并发编程/线程池.html](/编程语言/JAVA/JAVA并发编程/线程池.html) 线程池是高效并发的关键组件,提供线程生命周期管理的高级抽象
- [/编程语言/JAVA/JAVA并发编程/并发工具类.html](/编程语言/JAVA/JAVA并发编程/并发工具类.html) JUC 同步工具类,是落地并发控制思想的具体手段
- [/编程语言/JAVA/JAVA并发编程/并发集合.html](/编程语言/JAVA/JAVA并发编程/并发集合.html) 线程安全数据结构,体现实例封闭与线程安全委托模式
- [/编程语言/JAVA/JVM/JAVA内存模型.html](/编程语言/JAVA/JVM/JAVA内存模型.html) JMM 定义多线程内存访问规则,是可见性、原子性、有序性的基础
- [/操作系统/进程与线程.html](/操作系统/进程与线程.html) 操作系统层面的进程与线程概念,是理解线程调度与同步的基础
- [/软件工程/架构/系统设计/高并发.html](/软件工程/架构/系统设计/高并发.html) 高并发系统设计是并发原理的实际应用场景
- [/编程语言/并发模型.html](/编程语言/并发模型.html) 不同编程语言的并发模型比较,有助于理解 Java 模型的取舍
- [/计算机网络/IO模型.html](/计算机网络/IO模型.html) IO 模型与并发编程密切相关,尤其在高并发网络场景