Java 并发编程

一、并发编程的本质问题(第一性原理层)

并发编程并不是关于“多线程”,而是关于在不确定时序下,对共享状态的控制问题

1. 并发的三个永恒问题

所有并发 Bug,本质上都可以归结为以下三类之一:

  1. 可见性(Visibility)一个线程对状态的修改,是否能被其他线程观察到。

  2. 原子性(Atomicity)一个操作是否不可被中断、不可被拆分。

  3. 有序性(Ordering)程序执行顺序在不同线程观察下是否一致。

这三者是跨语言、跨平台、跨时代的并发本质问题。


二、并发控制的核心思想(跨语言稳定层)

这一层不依赖 Java,也不依赖 JVM,而是并发系统设计的通用思想。

2.1 不共享是最高级的并发安全

并发问题的根源在于共享,因此:

不共享 = 天然线程安全

线程封闭(Thread Confinement)

常见形式:

封闭是一种“架构选择”,不是语法技巧。


2.2 只读共享:不变性(Immutability)

如果共享不可避免,下一优先级是:

共享但不可变

不变对象的并发安全来自其数学属性,而非同步机制。

不变性的三个条件:

不变性是并发世界中最强的确定性来源。


2.3 受控共享:同步与协作

当对象既需要共享,又必须可变:

并发的核心任务 = 协调对状态的访问顺序

这引出了同步、锁、条件等待等机制。


三、对象共享与发布模型(并发设计主线)

3.1 对象生命周期视角

并发安全问题,本质是对象生命周期与线程生命周期不一致

关键问题:


3.2 发布与逸出

构造期间逸出是最危险的并发错误之一。


3.3 安全发布(Safe Publication)

安全发布不是“是否加锁”,而是建立可见性与有序性保证

通用安全发布策略:

没有安全发布,线程安全无从谈起。


四、并发类的设计模式(架构层)

4.1 实例封闭(Instance Confinement)

将线程不安全对象封装在一个受控的并发边界内。

这是最常见、也是最稳健的并发类设计方式。


4.2 线程安全委托(Delegation)

将并发安全责任交给更底层的线程安全组件。

前提:

委托失败,往往源于“多个原子操作组合后不再原子”。


4.3 状态依赖操作

并发系统中最复杂的不是互斥,而是:

操作是否依赖于状态是否满足某个条件

这类操作需要:


五、等待、通知与协作机制

5.1 等待-通知的本质模型

等待不是“睡眠”,而是:

在条件未满足时,主动让出执行权,并等待条件变化的通知

核心原则:


5.2 条件队列与显式条件

条件队列解决的是:

它体现的是状态机式并发设计思想


六、取消、关闭与线程生命周期管理

6.1 取消不是强制终止

并发系统中:

取消是一种协作协议,而非控制命令

线程必须自行决定:


6.2 中断的语义

中断不是异常,而是:

一种跨线程的协作信号

设计原则:


6.3 基于任务的取消

Future、Executor 的意义在于:


七、性能与伸缩性的并发视角

7.1 并发的成本模型

并发不是免费的:

并发的目标不是“线程更多”,而是“等待更少”。


7.2 锁竞争的本质

竞争强度取决于:

优化方向:


八、JVM 层面的并发优化(实现细节层)

本章属于了解即可,不应作为设计依据。

这些优化的前提是:

你的并发设计本身是合理的


九、并发程序的测试哲学

9.1 并发测试的困难

并发 Bug 是:


9.2 测试关注点


十、并发系统的工程哲学(长期稳定知识)

一个优秀的并发系统,应该让并发问题难以出现,而不是容易修复

关联内容(自动生成)