线程是什么,为什么使用线程,以及它和进程的区别
讲完进程之后,下一步最自然就是线程。
线程是面试里最常见也最容易讲乱的概念之一。很多人只会背:
- 进程是资源分配单位
- 线程是调度单位
但如果不理解“为什么要有线程”,这些话就容易变成死记硬背。
一、为什么使用线程
线程出现的核心目的,是在同一个进程内部实现更轻量的并发。
如果所有并发都用进程来做,会有几个问题:
- 进程创建成本更高
- 进程切换成本更高
- 进程间通信更麻烦
- 资源隔离太强,协作不够方便
而线程允许我们在同一个进程里拆出多个执行流,让它们共享:
- 代码段
- 数据段
- 堆
- 打开的文件
- 地址空间
这样多个任务就可以:
- 协作更方便
- 通信更直接
- 切换成本更低
这也是为什么很多服务程序、GUI 程序、浏览器和中间件都大量使用线程。
二、什么是线程
线程可以理解成:
进程中的一个执行流。
一个进程里可以只有一个线程,也可以有多个线程。多个线程共同共享进程的大部分资源,但每个线程都有自己独立的执行现场。
线程自己通常会保存:
- 程序计数器
- 寄存器现场
- 栈
- 线程状态
所以线程不是“没有自己的东西”,而是:
共享资源,但有独立执行现场。
三、线程和进程最本质的区别
最本质的一句话就是:
进程是资源分配的基本单位,线程是 CPU 调度的基本单位。
进程更强调什么
- 独立地址空间
- 独立资源边界
- 隔离性强
线程更强调什么
- 进程内并发
- 执行流
- 调度粒度更细
四、线程和进程具体区别有哪些
1. 地址空间
- 不同进程通常拥有独立地址空间
- 同一进程内线程共享地址空间
这也是为什么线程之间通信更方便,而进程之间默认隔离更强。
2. 资源归属
进程通常拥有独立资源边界,而线程共享进程的大部分资源。
3. 创建和切换成本
进程创建和切换通常更重,因为常常涉及:
- 页表
- 地址空间
- 内核资源
线程切换通常更轻,因为在同一进程内通常不需要切地址空间。
4. 通信方式
- 进程间通信需要借助 IPC 机制
- 线程之间可以直接通过共享变量、共享对象通信
5. 稳定性
- 一个进程崩溃,不一定影响其他进程
- 一个线程出现严重内存错误,可能把整个进程一起带崩
五、线程为什么通信方便但更容易出问题
因为线程共享同一进程的地址空间。
这意味着:
- 一个线程写入共享变量
- 另一个线程可以立刻看到
所以线程间通信非常直接。
但反过来也意味着:
- 多个线程会同时操作同一份数据
- 很容易出现竞态条件
- 容易有线程安全问题
因此线程模型通常需要配合同步机制,比如:
- 互斥锁
- 信号量
- 条件变量
六、一个线程崩溃,其他线程会怎样
这要分情况。
如果只是线程正常退出,或者某些语言运行时里的普通线程异常,可能只是该线程结束,其他线程还能继续运行。
但如果线程触发的是致命错误,比如:
- 段错误
- 非法内存访问
- 堆破坏
abort
那么由于线程共享进程的大部分资源,整个进程通常会被操作系统终止,其他线程也会一起结束。
七、小结
进程是资源分配的基本单位,拥有独立的地址空间和系统资源;线程是 CPU 调度的基本单位,是进程中的一个执行流。同一进程内的线程共享代码段、数据段、堆和打开的文件等资源,但每个线程有自己独立的栈、寄存器和程序计数器。相比进程,线程的创建、切换和通信开销通常更小,但由于共享内存,也更容易出现同步和线程安全问题。
八、总结
线程的出现是为了在同一个进程内部实现更轻量的并发。进程强调资源边界和隔离,线程强调执行流和调度。线程共享进程的大部分资源,因此通信方便、切换较轻,但也更容易出现同步冲突和线程安全问题。理解了线程和进程的资源边界差异,后面再学线程上下文切换、线程实现模型、同步互斥和死锁就会自然很多。
