线程和进程有什么区别?
- 标签:操作系统、计算机基础
🏛 业务架构师
核心区别一条:进程是资源分配单位(独立内存空间),线程是调度执行单位(共享所属进程的内存)。由此派生:进程隔离彻底——一个崩了别的没事,但创建/切换/通信成本高;线程轻量、共享内存通信零拷贝,但一个线程写坏共享数据全进程陪葬。
业务视角我把这对概念对应到三个真实决策:
- 故障域设计:浏览器每个标签页独立进程、微服务每个服务独立进程——用进程隔离换取故障不扩散。"推荐服务崩溃不能拖垮交易服务"这类业务诉求,物理答案就是进程边界。反例是"把十个模块塞进一个单体进程",一个内存泄漏全站重启;
- 性能与成本的权衡:进程内多线程共享内存,通信成本近乎零——这是把强耦合、高频协作的模块放同一进程的理由(订单计算引擎内部多线程并行),也是"不要过度拆微服务"的物理依据:跨进程 RPC 比进程内调用慢几个数量级,拆分要拿"隔离收益"覆盖"通信成本";
- 容器时代的新形态:K8s 里一个 Pod 共享网络与存储,进程即部署单元——组织架构按进程边界划分所有权(谁 deploy、谁 oncall),Conway 定律在这里体现得最直白。
引申一个高频追问:什么时候多进程优于多线程——需要强隔离(插件系统、跑用户脚本)、需要利用多机扩展、或语言生态限制(Node 单线程用多进程压多核)时。隔离与效率的定价,是这对概念留给架构师的题。
🏗 系统架构师
经典对比,我从资源、通信、切换成本三个维度讲:
- 资源与隔离:进程是资源分配单位(独立虚拟地址空间、文件描述符、信号处理),一个进程崩溃不影响其他进程,隔离强;线程是调度执行单位,同进程线程共享堆、全局变量、文件句柄,通信零成本但也因此互相能"弄脏"数据,一个线程段错误整个进程退出;
- 切换成本:进程切换要换页表(TLB 失效)、切内核上下文,微秒级偏重;线程切换只换寄存器与栈,同进程地址空间不动,更轻;
- 通信方式:进程间要 IPC——管道、消息队列、共享内存、信号量、socket;线程间直接读写共享变量 + 锁/队列同步。
架构视角的引申(关键加分):
- 隔离性与共享性是可靠性与效率的权衡:微服务 = 把"进程隔离"推到机器级(故障隔离、独立部署、语言异构),代价是网络 IPC 的性能与复杂度;线程共享内存 = 最高效的并发模型,代价是并发 bug 与故障传播;
- 语言趋势:Go 的 goroutine、Java 21 虚拟线程都在"比线程更轻的调度单元"上卷,本质是把"共享内存 + 轻量切换"推向极限,我评估高并发技术栈时会重点看它提供哪种并发原语。
💻 全栈开发专家
进程是资源分配的最小单位,线程是 CPU 调度的最小单位——线程是进程内的执行流,共享进程资源。
| 维度 | 进程 | 线程 |
|---|---|---|
| 地址空间 | 独立 | 共享进程的堆/方法区 |
| 私有部分 | 全部 | 栈、程序计数器、局部变量 |
| 通信 | 管道/消息队列/共享内存/信号量(重) | 直接读写共享变量(快但要同步) |
| 切换成本 | 高(切页表、刷 TLB) | 低 |
| 隔离性/稳定性 | 一个崩不牵连 | 一个线程崩整个进程挂 |
工程视角的对应关系(这么答才像干过活):
- Java 内存模型就是"多线程共享堆"的直接映射:JVM 里所有线程共享堆和方法区,所以才有可见性/竞态问题;线程私有的是虚拟机栈和 PC。
- 为什么浏览器/Chrome 多进程:一个 tab 崩不影响其他——用进程隔离换稳定;插件渲染独立进程是安全沙箱。
- 为什么 Nginx/Redis 单(少)进程多线程/IO 多路复用:线程切换虽比进程便宜,但万级线程照样扛不住上下文切换,于是事件驱动接管。
- 协程/虚拟线程(JDK21):用户态调度的"轻线程",把阻塞 IO 的线程占用成本降到极低,是线程模型在 IO 密集场景的演进答案。
通信选择:跨隔离/跨机器用进程间通信(或 MQ);共享状态并发用 JUC 工具,别裸 new Thread 共享变量。