Java 线程
一、并发的第一性问题:为什么需要线程?
在任何并发系统中,都必须回答三个根本问题:
- **执行单元是什么?**(谁在运行)
- **如何被调度?**(谁决定何时运行)
- **如何等待与协作?**(如何处理依赖与阻塞)
1.1 执行单元的抽象
线程 = 可被调度的最小执行上下文
一个线程本质上由以下要素构成:
- 执行栈(方法调用与局部变量)
- 程序计数器(当前执行位置)
- 寄存器快照(CPU 上下文)
- 阻塞 / 唤醒语义(等待条件)
线程并不拥有资源,资源属于进程;线程只是共享资源上的执行路径。
二、进程与线程:资源与执行的分离
2.1 进程的本质角色
进程 = 资源容器
- 地址空间
- 文件句柄
- 网络连接
- 安全上下文
2.2 线程的本质角色
线程 = 调度与执行的载体
同一进程内的线程:
- 共享内存
- 独立栈
- 独立调度
这正是 Java 并发模型选择“共享内存 + 线程”的根本原因。
三、Java 线程模型的设计哲学
3.1 Java 为什么直接建模 Thread?
Java 选择 Thread 作为一等公民,背后隐含了三条设计哲学:
- **拥抱操作系统调度**(而非自建调度器)
- **阻塞是合法且可表达的语义**
- **并发通过共享内存完成,而非消息复制**
这决定了:
- synchronized / wait / notify 的存在
- Thread 与 OS 线程的一一映射(平台线程)
3.2 平台线程模型(传统 Java)
Java Thread ≈ OS Native Thread
特点:
- 创建成本高
- 阻塞即占用 OS 线程
- 调度依赖内核
这是 Java 并发长期以来的性能与伸缩性瓶颈。
四、线程的抽象层次结构(核心升维)
4.1 抽象层(稳定、不变)
- 执行上下文
- 调度
- 阻塞与唤醒
4.2 JVM 实现层(相对稳定)
- Thread 对象
- 线程状态机
- wait / park / interrupt
4.3 工程使用层(易变)
- Thread / Runnable / Callable
- 线程池
- 虚拟线程
理解并发的关键,在于始终知道自己处在哪一层。
五、Runnable / Callable / Thread:职责拆分模型
5.1 核心思想:执行与调度解耦
| 抽象 | 职责 |
|---|---|
| Runnable / Callable | 描述“要做什么” |
| Thread | 描述“如何被调度执行” |
这是一种典型的 Command + Executor 思想。
5.2 为什么推荐 Runnable 而非继承 Thread
- 解除继承限制
- 支持任务复用
- 天然适配线程池与调度器
Thread 是执行载体,不应承载业务逻辑。
六、线程生命周期与状态机(行为模型)
6.1 状态机的本质意义
线程状态并非 API 细节,而是:
调度器与同步原语协作的结果
核心状态语义:
- RUNNABLE:可被调度
- BLOCKED:竞争锁失败
- WAITING / TIMED_WAITING:主动让渡 CPU
- TERMINATED:生命周期结束
6.2 join / wait 的统一原理
- join 本质:**当前线程在目标线程对象上 wait**
- interrupt 本质:**协作式中断信号,而非强制终止**
并发的安全性来自:
约定 + 协作,而非抢占式控制
七、线程调度的不可控性原则
7.1 抢占式调度的现实
- Java 使用抢占式调度
- 优先级只是“调度建议”
7.2 设计原则
不要试图通过 Thread API 精确控制执行顺序
正确做法:
- 使用同步原语表达依赖
- 使用并发工具类表达约束
八、虚拟线程:并发模型的范式升级
8.1 虚拟线程解决的根本问题
阻塞语义 vs 资源利用率 的长期冲突
传统模型的问题不是“线程慢”,而是:
- 阻塞 = 占用 OS 线程
- OS 线程 = 稀缺资源
8.2 虚拟线程的本质
虚拟线程 = 用户态调度的执行上下文
关键特征:
- 仍然保留阻塞语义
- 阻塞时从平台线程卸载
- 由 JVM 调度到 carrier thread
8.3 虚拟线程在并发模型中的位置
| 模型 | 核心思想 | 代价 |
|---|---|---|
| 线程池 | 控制线程数量 | 编程复杂度 |
| Reactor | 非阻塞 IO | 心智负担 |
| 虚拟线程 | 阻塞语义 + 协程调度 | JVM 实现复杂度 |
虚拟线程降低了并发编程的门槛,而非替代所有模型。
九、统一视角下的线程哲学
9.1 Java 并发的核心信条
- 阻塞是合法的
- 中断是协作的
- 顺序通过同步表达
- 性能来自模型选择,而非 API 技巧
9.2 面向未来的稳定认知
- Thread 是执行抽象,不是业务模型
- 并发能力 = 执行模型 × 调度策略 × 资源成本
- 虚拟线程是 Java 并发的长期方向
十、总结
线程不是并发的目的,而是并发的一种表达方式。
理解线程,最终是理解:
- 执行
- 调度
- 阻塞
- 协作
关联内容(自动生成)
- [/编程语言/JAVA/JAVA并发编程/JAVA并发编程.html](/编程语言/JAVA/JAVA并发编程/JAVA并发编程.html) Java并发编程的整体概述,与线程作为执行单元的概念密切相关
- [/编程语言/JAVA/JAVA并发编程/基础概念.html](/编程语言/JAVA/JAVA并发编程/基础概念.html) Java并发编程的基础概念,与线程的基本原理和设计哲学相关
- [/编程语言/JAVA/JAVA并发编程/线程池.html](/编程语言/JAVA/JAVA并发编程/线程池.html) 线程池是对线程概念的实际应用,用于管理和复用线程资源
- [/编程语言/JAVA/JAVA并发编程/并发工具类.html](/编程语言/JAVA/JAVA并发编程/并发工具类.html) 并发工具类提供了线程间协作的高级机制,与线程的阻塞和协作密切相关
- [/编程语言/JAVA/JAVA并发编程/并发集合.html](/编程语言/JAVA/JAVA并发编程/并发集合.html) 并发集合是多线程环境下安全的数据结构,与线程安全和资源共享相关
- [/编程语言/JAVA/JVM/JVM.html](/编程语言/JAVA/JVM/JVM.html) JVM是Java线程的运行环境,理解JVM有助于深入理解线程的执行机制
- [/编程语言/JAVA/JAVA并发编程/Disruptor.html](/编程语言/JAVA/JAVA并发编程/Disruptor.html) Disruptor是高性能并发框架,展示了线程并发的高级应用
- [/编程语言/并发模型.html](/编程语言/并发模型.html) 并发模型提供了多种并发实现方式,与Java线程模型形成对比和补充
- [/操作系统/进程与线程.html](/操作系统/进程与线程.html) 操作系统层面的进程与线程概念,是理解Java线程的基础
- [/编程语言/JAVA/JVM/JAVA内存模型.html](/编程语言/JAVA/JVM/JAVA内存模型.html) Java内存模型定义了线程间内存可见性规则,与线程协作密切相关