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):

Condition(显式条件队列) 相比 wait/notify 的增量:多条件分离、精准唤醒、可中断 / 可超时等待。它是状态机式并发设计的基础设施。

取消、中断与生命周期管理

Java 没有"强杀线程"——生命周期管理是一套协作协议

活跃性的 Java 预防

活跃性失效的原理(死锁 / 活锁 / 饥饿、Coffman 条件)见母篇「进度协调失效」。Java 层的预防手段:

问题Java 预防手段
死锁固定全局加锁顺序、tryLock(timeout) 超时放弃、一次性申请、缩小临界区
活锁随机退避(重试间隔随机化)、限制重试次数、引入协调者
饥饿公平锁 new ReentrantLock(true)、避免优先级反转、动态优先级提升

预防优于检测,设计优于补救。

JVM 锁优化

JVM 对 synchronized 做了一套自动优化,核心是按竞争程度逐级升级,避免无谓的重量级开销:

无锁 → 偏向锁 → 轻量级锁 → 重量级锁       (无竞争)  (轻度CAS竞争) (重度竞争挂起)
优化作用
偏向锁无竞争时偏向首个线程,省去 CAS(注:JDK 15 起默认废弃,JEP 374)
轻量级锁轻度竞争用 CAS 自旋,不挂起线程
自旋 / 自适应自旋短暂忙等避免上下文切换;自适应按历史动态调整自旋次数
锁消除JIT 判定不可能竞争(如未逸出的局部对象)直接去锁
锁粗化把连续的细粒度加锁合并,减少反复加解锁

前提:这些优化只能锦上添花,救不了本身不合理的并发设计

关联内容(自动生成)