1.进程
进程是操作系统进行资源分配和调度的基本单位,一个运行起来的Java程序就是一个进程。
补充:Java 进程的内存结构是在操作系统进程内存基础上,由 JVM 进一步划分(堆、方法区、虚拟机栈等),本质仍属于操作系统分配给 Java 进程的内存空间。
进程控制块(PCB)是操作系统内核为每个进程维护的核心数据结构。
简单来说:进程 = 程序代码 + 数据 + PCB
把多个线程组织起来,像linux操作系统,是用链表这样的形式(不一定是链表)把多个PCB串起来。
2.PCB的关键要点
- pid - 进程的身份标识符
- 内存指针:PCB 中的内存指针是操作系统为进程维护的核心地址标识字段,
- 进程的内存空间是操作系统分配的连续 / 离散地址区间,PCB 中的内存指针会记录这些区间的起始地址、结束地址、映射关系。
- 地址隔离:确保每个进程只能访问自己的内存区域(通过指针限定地址范围),防止越界访问。
- 内存管理 :操作系统通过指针快速找到进程的内存区域,便于分配 / 回收内存、处理页面置换(虚拟内存场景)
- 上下文恢复:进程切换时,结合内存指针恢复进程的地址空间,保证指令 / 数据能正确读取。
- 文件描述表
文件不一定是硬件,也有可能是网卡,在运行的时候,需要和硬盘进行交互,而硬盘上面的数据使用文件的形式来储存的。
- 进程调度
- 分时复用:操作系统为实现多进程 / 线程并发执行而采用的核心调度策略,本质是将 CPU 的物理时间切分成固定长度的 "时间片(Time Slice)",让多个进程 / 线程轮流占用 CPU 执行(每个任务仅占用一个时间片),从宏观上营造 "多个任务同时运行" 的效果,微观上 CPU 仍为串行执行。
- 进程状态:只有两个就绪状态和阻塞状态,就绪状态是随时准备好,随时准备好被调用。而阻塞状态就是进程/线程运行到这个位置的时候会阻塞等待(类似于卡住了)。
- 进程优先级:进程优先级是操作系统为进程分配 CPU、内存等资源的核心调度依据,本质是给不同进程划分 "资源获取优先级"------ 高优先级进程会优先获得 CPU 时间片、更优的内存分配策略,是操作系统实现多进程资源公平与高效分配的关键机制。
| 维度 | 进程优先级 | 线程优先级 |
|---|---|---|
| 作用范围 | 操作系统层面,针对整个进程(包含所有线程) | 进程内层面,仅影响进程内线程的 CPU 抢占 |
| 底层载体 | 存储在进程的 PCB(如 Linux task_struct)中 |
存储在线程的 TCB(线程控制块)中,依赖进程优先级的基础 |
| 核心影响 | 决定进程整体的 CPU 时间片总量、内存分配优先级 | 决定进程内线程对 CPU 时间片的分配比例 |
- 进程的记账信息: 统计每个进程在CPU上运行的时间,如果发现某个进程长时间没有被分配CPU资源,操作系统就会倾斜一点。
- 进程的上下文:是操作系统为了让进程恢复执行所需的所有状态信息的集合,简单来说:当进程被暂停执行时,操作系统会把它的 "运行状态" 完整保存下来(即上下文);当进程再次被调度执行时,又会基于这个快照恢复所有状态,就像进程从未暂停过一样。进程上下文是实现分时复用、进程切换的核心基础,所有信息最终都存储在进程的 PCB(进程控制块)中。
3. 线程
JVM 进程作为容器,每个进程最少一个线程,即一个进程中有1~n个线程,而1个线程的代码就叫做单线程代码。
而我们采用线程就是因为觉得创建/销毁一个进程的开销太大了。
进程是操作系统资源(CPU资源、内存、硬盘资源(文件表述符表)、网络带宽)分配的基本单位,而进程的内部管理着多个线程,多个线程会共享除CPU之外的其他资源,进程创建需要申请资源,销毁需要释放资源,而线程的创建,只有第一个线程在创建的时候才会申请资源,后续创建线程无需调用资源,只有所有线程全部销毁才会真正释放资源,某个线程执行结束,并不会销毁释放资源,进程和线程之间是相互独立的,是并发执行的执行者,但是一个进程中的线程可能会有一定的影响,比如:阻塞等待...
4.线程和进程的区别
- 资源隔离:进程就类似于一个人一个房间,而线程是一个房间多个人。
- 开销差别:进程类似于开一家分店,开销大,而线程是在店里面招人,仅需提供工位,共享店里面的所有资源,开销较少
- 稳定性:进程独立稳定 ,线程依赖于进程,且线程之间相互影响
- Java实例维度:进程保证隔离性 (多实例),线程提升并发效率(线程池),二者结合平衡性能与稳定性
- 简单来说:进程管 "资源隔离",线程管 "高效执行",Java 开发中需根据场景选择 ------ 要隔离选进程,要高效选线程,同时规避线程安全和进程切换的坑。
| 对比维度 | 进程(Process) | 线程(Thread) | Java 场景下的具体体现 |
|---|---|---|---|
| 本质定位 | 操作系统资源分配 / 隔离的基本单位 | 操作系统CPU 调度 / 执行的基本单位 | Java 进程 = JVM 实例(分配独立堆 / 元空间);Java 线程 = OS 原生线程(1:1 映射,调度权在 OS) |
| 资源占用 | 独立占用资源:✅ 虚拟内存空间(堆 / 代码段)✅ 文件句柄 / Socket✅ 进程级 PCB(存储资源信息) | 共享进程资源,仅私有少量执行资源:✅ 私有:线程栈 / 程序计数器 / 寄存器✅ 共享:进程的堆 / 文件句柄 / 元空间 | Java 多线程共享堆内存(如静态变量),ThreadLocal通过线程私有映射实现隔离;每个线程有独立虚拟机栈 |
| 创建 / 销毁开销 | 高:需分配 / 回收全部资源(内存、句柄等),耗时 ms 级 | 低:仅需创建私有栈 / TCB(线程控制块),耗时 μs 级 | Java 中new Thread().start()比启动新 Java 进程(如Runtime.exec())快 100 + 倍;线程池减少线程创建开销 |
| 上下文切换开销 | 高:需切换页表、资源表、CPU 寄存器等,耗时 1~10μs | 低:仅切换线程栈、寄存器,耗时 0.1~1μs | Java 进程内线程切换无内存地址空间切换;过多线程(如数百个)仍会因切换导致 CPU 飙升 |
| 通信方式 | 复杂(跨进程 IPC):Socket / 管道 / 共享内存 / 消息队列 | 简单(进程内共享):直接读写共享变量 + 锁(synchronized/Lock) | Java 进程间通信需 Redis/MQ/HTTP;线程间可直接用ConcurrentHashMap共享数据(需线程安全) |
| 独立性 / 隔离性 | 高:进程间完全隔离,一个崩溃不影响其他进程 | 低:线程共享进程资源,一个崩溃可能导致整个进程终止 | 一个 Java 进程崩溃(如 OOM)不影响其他 Java 进程;线程抛未捕获Error可能导致 JVM 退出 |
| 调度粒度 | 操作系统间接调度(通过进程内线程) | 操作系统直接调度 | Java 进程的 CPU 占用 = 内部所有线程 CPU 占用总和;OS 调度 Java 线程而非进程 |
| 标识 ID | 系统全局唯一 PID(存储在 PCB) | 进程内唯一 TID,系统全局可能重复(存储在 TCB) | jps查 Java 进程 PID;jstack <PID>查线程 TID(16 进制);Thread.getId()仅进程内唯一 |
| 生命周期 | 独立:从启动到终止,不受其他进程影响 | 依赖进程:进程终止则所有线程强制销毁 | Java 进程终止(如System.exit(0))会销毁所有线程;主线程结束不影响守护线程(如 GC 线程) |
| 优先级作用 | 决定进程整体 CPU 时间片配额 | 决定进程内线程对时间片的分配比例 | Linux 下nice调整 Java 进程优先级;Thread.setPriority()仅影响进程内线程调度(OS 可忽略) |