Java 并发编程基础概念
一、并发的第一性原理(Why)
1. 并发问题的本质
并发问题 ≠ 多线程问题
并发问题产生的充分必要条件是:
多个执行主体 + 共享的可变状态 + 时间上的交错执行
只要满足以上三个条件之一被消除,并发问题就不会出现:
- 不共享 → 无并发问题
- 不可变 → 无并发问题
- 无时间交错(串行) → 无并发问题
2. 并发失效的根源:观察不一致
并发错误的本质不是“写错代码”,而是:
一个线程基于已经失效的观察结果做出了决策
这会导致典型问题:
- 竞态条件(Race Condition)
- 脏读、不可重复读
- 单例失效、状态错乱
3. 并发必须满足的三大约束目标
所有并发控制手段,本质上都在解决以下三个问题之一或多个:
| 约束目标 | 根本问题 | 核心含义 |
|---|---|---|
| 原子性 | 操作被打断 | 要么全做,要么不做 |
| 可见性 | 观察失效 | 状态修改对他人可见 |
| 有序性 | 指令重排 | 因果顺序不被破坏 |
👉 并发工具的差异,本质是它们解决这三类约束的能力不同。
二、线程安全的抽象模型(What)
1. 线程安全的本质定义
当多个线程并发访问某个对象时,无论执行顺序如何、是否发生交错,只要对象始终能维持其不变式(Invariant),则称该对象是线程安全的。
⚠️ 线程安全与“全局变量 / 静态变量”没有必然因果关系,真正的风险来源是:
共享 + 可变 + 未受控访问
2. 线程安全的经典分类(稳定认知模型)
| 分类 | 抽象定义 | 设计含义 |
|---|---|---|
| 绝对线程安全 | 调用方无需任何同步 | 内部完全自洽,代价最高 |
| 相对线程安全 | 单次操作安全 | 组合操作需外部协作 |
| 线程兼容 | 自身不安全 | 可通过调用方同步保证 |
| 线程对立 | 无法安全并发使用 | 设计上排斥并发 |
👉 这是并发设计的边界说明书,而不是实现技巧。
3. 不可变性:最强的并发策略
不可变对象天然线程安全
设计哲学:
- 状态只在构造期确定
- 之后永不变化
- 并发复杂度直接归零
这是所有并发控制中:
成本最低、收益最高、最稳定的方案
三、并发控制的设计哲学(How · Strategy)
1. 并发控制的三种核心策略
| 策略 | 核心思想 | 典型方式 |
|---|---|---|
| 互斥 | 同一时间只允许一个执行者 | 锁 / Monitor |
| 乐观 | 冲突是小概率事件 | CAS / 版本校验 |
| 隔离 | 根本不共享状态 | 不可变 / 线程封闭 |
👉 并发设计的第一选择顺序应是:
隔离 → 乐观 → 互斥
2. 悲观并发 vs 乐观并发(哲学差异)
悲观并发:
- 假设冲突必然发生
- 先加锁,再执行
- 代价是阻塞和上下文切换
乐观并发:
- 假设冲突是例外
- 先执行,失败再补偿
- 代价是自旋和重试
👉 这是性能与确定性之间的取舍问题。
3. 阻塞 vs 非阻塞算法
在非阻塞算法中,一个线程的失败或挂起不会导致其他线程的失败或挂起。
这是并发系统**可伸缩性(Scalability)**的关键。
四、并发机制模型(How · Mechanism)
1. Java 内存模型(JMM)
JMM 不是内存结构,而是:
关于“何时可见、何时有序、何时允许重排”的规则集合
核心目标:
- 屏蔽硬件与编译器差异
- 定义 Happens-Before 关系
2. Happens-Before:并发世界的因果律
Happens-Before 不是时间先后,而是:
结果可见性与因果保证
关键规则:
- 程序次序规则
- volatile 规则
- 监视器锁规则
- 传递性
3. Monitor 模型(互斥的抽象基础)
Monitor 提供了:
- 互斥访问
- 条件等待(Wait / Notify)
- 内存可见性保证
这是 synchronized 的理论原型。
4. CAS 与 CPU 原语
CAS(Compare-And-Swap)是:
由硬件直接支持的原子比较与更新指令
特点:
- 非阻塞
- 高并发友好
- 存在 ABA 与自旋成本
五、Java 并发工具的能力映射(How · Tool)
1. 并发能力 × Java 工具矩阵
| 并发能力 | 抽象机制 | Java 实现 |
|---|---|---|
| 互斥 | Monitor | synchronized / Lock |
| 可见性 | Happens-Before | volatile |
| 原子更新 | CAS | AtomicX |
| 非阻塞 | 无锁算法 | CAS + 自旋 |
2. synchronized 的设计定位
synchronized 不是“慢”,而是:
最安全、最完整、语义最强的并发原语
它同时提供:
- 互斥
- 可见性
- 有序性
锁升级(偏向 → 轻量 → 重量)体现的是:
JVM 对不同竞争强度的自适应优化
3. volatile 的设计定位
volatile 只解决:
- 可见性
- 有序性
但不提供互斥。
适用场景:
- 状态标志
- 生命周期控制
- 单次写、多次读
4. CAS 的设计定位
CAS 是:
以 CPU 指令换取锁阻塞的性能方案
适合:
- 冲突概率低
- 操作时间短
- 可接受重试成本
六、并发设计的稳定选型原则(Guideline)
- **能不共享,就不共享**(隔离优先)
- **能不可变,就不可变**(设计优先)
- **能无锁,就无锁**(乐观优先)
- **必须互斥,才加锁**(兜底方案)
- **先保证正确性,再谈性能**
七、并发模型的演进:从线程到纤程
1. 传统线程模型的瓶颈
- 1:1 映射内核线程
- 切换成本高
- 并发规模受限
2. 协程 / 纤程的核心思想
新并发模型拆分为:
- **Continuation(执行过程)**:保存与恢复上下文
- **Scheduler(调度器)**:决定何时运行
目标不是“更快”,而是:
用更低成本管理更大规模的并发
关联内容(自动生成)
- [/编程语言/JAVA/JVM/JVM.html](/编程语言/JAVA/JVM/JVM.html) JVM的内存模型和执行机制是理解Java并发编程的基础,特别是JMM与JVM内存结构的关系
- [/编程语言/JAVA/JVM/自动内存管理/垃圾回收.html](/编程语言/JAVA/JVM/自动内存管理/垃圾回收.html) 垃圾回收过程中的并发与并行处理与Java并发编程中的线程协调机制密切相关
- [/编程语言/JAVA/JVM/JAVA内存模型.html](/编程语言/JAVA/JVM/JAVA内存模型.html) Java内存模型(JMM)是Java并发编程的核心理论基础,详细阐述了内存可见性、原子性和有序性问题
- [/中间件/数据库/数据库系统/事务管理/事务.html](/中间件/数据库/数据库系统/事务管理/事务.html) 数据库事务的ACID特性与并发控制和Java并发编程中的原子性、一致性概念相通
- [/操作系统/进程与线程.html](/操作系统/进程与线程.html) 操作系统层面的进程与线程管理机制为Java并发编程提供了底层基础
- [/编程语言/JAVA/语言基础.html](/编程语言/JAVA/语言基础.html) Java语言基础特性是理解并发编程的前提,包括对象模型、内存分配等
- [/软件工程/架构/系统设计/高并发.html](/软件工程/架构/系统设计/高并发.html) 高并发系统设计实践应用了Java并发编程的基本原理和工具
- [/编程语言/JAVA/JAVA并发编程/线程池.html](/编程语言/JAVA/JAVA并发编程/线程池.html) 线程池是Java并发编程的重要组成部分,是对基础线程概念的应用和扩展
- [/编程语言/JAVA/JAVA并发编程/并发工具类.html](/编程语言/JAVA/JAVA并发编程/并发工具类.html) 并发工具类是Java并发编程基础概念的具体实现
- [/编程语言/JAVA/JAVA并发编程/线程.html](/编程语言/JAVA/JAVA并发编程/线程.html) 线程是Java并发编程的基本执行单元,与本文档中的线程安全概念密切相关
- [/编程语言/JAVA/高级/NIO.html](/编程语言/JAVA/高级/NIO.html) Java NIO中的并发处理与本文档中的并发概念密切相关
- [/编程语言/JAVA/框架/Spring/Spring.html](/编程语言/JAVA/框架/Spring/Spring.html) Spring框架中的并发处理和事务管理与Java并发编程基础概念相关