0. 进程与线程
进程是应用程序在某块独立内存上的运行活动,是系统进行资源分配的基本单位。各个进程之间互不干扰,包括程序段、数据、PCB。
- 程序段:程序运行的代码;
- 数据段:程序运行期的相关数据;
- PCB 进程控制块:描述进程的基本情况和运行状态,控制和管理进程。是进程存在的唯一标识。
线程是进程的子任务,线程依赖于进程存在,每个进程可以包含多个线程。线程是CPU进行任务调度的基本单位。
0.1 进程与线程的区别
- 进程是一个独立的运行环境,而线程是在进程中执行的一个任务,线程依赖于进程而存在。他们本质的区别是是否单独占有内存地址空间及其它系统资源(比如I/O):
- 数据共享与数据同步:进程单独占有内存地址空间,所以数据共享复杂但是同步简单,各个进程之间互不干扰;而多个线程共享其所属进程的内存地址空间和资源,数据共享简单,但是同步复杂。
- 可靠性:多进程比多线程更可靠,一个进程出现问题不会影响其他进程,不影响主程序的稳定性,可靠性高;一个线程崩溃可能影响整个程序的稳定性,可靠性较低。
- 创建、切换的复杂性:进程是重量级的,而线程是轻量级的。进程的创建和销毁不仅需要保存寄存器和栈信息,还需要资源的分配回收以及页调度,开销较大;线程只需要保存寄存器和栈信息,开销较小。
- 进程是操作系统进行资源分配的基本单位,而线程是CPU调度的基本单位。线程切换不会引起进程切换。
进程的状态
- 创建:分配资源,创建PCB;
- 就绪:准备运行,等待CPU时间片;
- 运行:正在CPU上运行;
- 阻塞:进程等待某一事件而暂停运行,如等待资源可用或IO完成;
- 结束:进程结束,进行资源释放与回收。
进程通信
- 共享内存
- 消息队列:发送消息到缓冲队列,然后另一个进程接收
- 管道通信:管道是连通读进程与写进程的pipe文件,管道是半双工的,同一时刻单向传输。
线程通信
线程通信通过共享变量,线程同步采用锁、信号量等机制。
多进程与多线程的选择问题
- 需要频繁创建、销毁时用线程;
- 在稳定性优先的环境中,使用多进程,保证系统的可靠性;
协程
协程比线程更轻量级,它运行在用户态。协程运行时在方法内部是可中断的,然后转而执行其他协程。协程相当于在同一个线程中的并发。
协程的执行效率很高,协程的切换由程序自己控制,没有线程切换的开销。
协程中控制共享资源可以不加锁,通过判断状态来进行,因此执行效率更高。
0.2 上下文切换
上下文指某一时间点的 CPU 寄存器和程序计数器的内容。
上下文切换是指 CPU 从一个进程(线程)切换到另一个进行(线程)。
CPU 为某个线程分配 CPU 时间片来实现多线程机制,CPU 通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。
- 在任务切换前会保存上一个任务的运行状态,该任务从保存到加载的过程就是一次上下文切换。
0.3 线程的实现
线程的 3 种实现方式:
- 直接使用内核线程 1:1 实现
- 使用用户线程 1:N实现
- 使用用户线程+轻量级线程混合实现 N:M实现
0.3.1 内核线程实现
内核线程直接由操作系统内核来支持,并由内核来完成线程切换,内核通过操作调度器对线程进行调度,并将线程映射到处理器上。
内核线程的升级版是轻量级进程,每个轻量级进程对应一个内核线程。1:1的对应关系。
缺点是:
- 线程操作需要进行系统调用,代价高,需要在用户态和内核态之间来回切换。切换的主要成本在于响应中断、保护和恢复现场。
- 要占用内核资源,如内核线程的栈空间,从而限制了线程数量。
0.3.2 用户线程实现
用户线程指完全建立在用户空间的线程库上,内核不能感知用户线程的存在及具体实现。
- 用户线程的建立、同步、销毁、调度完全在用户态进行,不需要内核的帮助。
- 快速、高效,支持大规模。
0.3.3 混合实现
既存在轻量级线程,又存在用户线程。轻量级线程作为用户线程和内核线程之间的桥梁,用户线程的系统调用要通过轻量级进程来实现。
0.3.4 Java 中的线程实现
主流 JVM 采用直接把 Java 线程一对一映射到操作系统的原生线程,中间没有额外的间接结构,底层完全由操作系统来解决。也有少数的 JVM 采用其他两种线程的实现方式。
0.4 Java 线程调度
线程调度是指 CPU 为线程分配时间片的过程。
线程调度有两种方式:
- 协同式调度 Cooperative Threads-Scheduling
- 抢占式调度 Preemptive Threads-Scheduling
Java 中使用的是抢占式调度。
线程调度可以通过设置线程的优先级来给操作系统建议,Java 中线程优先级有十种。但是线程调度最终还是操作系统决定。因为:
- 操作系统的优先级数目可能比 Java 中的线程优先级数目少,如 Windows 中就只有 7 种,所以 Java 中不同的优先级可能对应到相同的操作系统优先级。
- 优先级可能会被系统自动改变。
0.5 线程同步
线程同步指多个线程访问同一个资源应该互斥访问。当有一个线程正在访问该资源时,其他线程都应等待,直到该线程访问结束。