进程与线程


0. 进程与线程

进程是应用程序在某块独立内存上的运行活动,是系统进行资源分配的基本单位。各个进程之间互不干扰,包括程序段、数据、PCB。

  • 程序段:程序运行的代码;
  • 数据段:程序运行期的相关数据;
  • PCB 进程控制块:描述进程的基本情况和运行状态,控制和管理进程。是进程存在的唯一标识

线程是进程的子任务,线程依赖于进程存在,每个进程可以包含多个线程。线程是CPU进行任务调度的基本单位。

0.1 进程与线程的区别

  1. 进程是一个独立的运行环境,而线程是在进程中执行的一个任务,线程依赖于进程而存在。他们本质的区别是是否单独占有内存地址空间及其它系统资源(比如I/O):
    • 数据共享与数据同步:进程单独占有内存地址空间,所以数据共享复杂但是同步简单,各个进程之间互不干扰;而多个线程共享其所属进程的内存地址空间和资源,数据共享简单,但是同步复杂。
    • 可靠性:多进程比多线程更可靠,一个进程出现问题不会影响其他进程,不影响主程序的稳定性,可靠性高;一个线程崩溃可能影响整个程序的稳定性,可靠性较低。
    • 创建、切换的复杂性:进程是重量级的,而线程是轻量级的。进程的创建和销毁不仅需要保存寄存器和栈信息,还需要资源的分配回收以及页调度,开销较大;线程只需要保存寄存器和栈信息,开销较小。
  2. 进程是操作系统进行资源分配的基本单位,而线程是CPU调度的基本单位。线程切换不会引起进程切换。

进程的状态

  1. 创建:分配资源,创建PCB;
  2. 就绪:准备运行,等待CPU时间片;
  3. 运行:正在CPU上运行;
  4. 阻塞:进程等待某一事件而暂停运行,如等待资源可用或IO完成;
  5. 结束:进程结束,进行资源释放与回收。

进程通信

  1. 共享内存
  2. 消息队列:发送消息到缓冲队列,然后另一个进程接收
  3. 管道通信:管道是连通读进程与写进程的pipe文件,管道是半双工的,同一时刻单向传输。

线程通信

线程通信通过共享变量,线程同步采用锁、信号量等机制。

多进程与多线程的选择问题

  1. 需要频繁创建、销毁时用线程;
  2. 在稳定性优先的环境中,使用多进程,保证系统的可靠性;

协程

协程比线程更轻量级,它运行在用户态。协程运行时在方法内部是可中断的,然后转而执行其他协程。协程相当于在同一个线程中的并发。

协程的执行效率很高,协程的切换由程序自己控制,没有线程切换的开销。

协程中控制共享资源可以不加锁,通过判断状态来进行,因此执行效率更高。

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 为线程分配时间片的过程。

线程调度有两种方式:

  1. 协同式调度 Cooperative Threads-Scheduling
  2. 抢占式调度 Preemptive Threads-Scheduling

线程调度的两种方式

Java 中使用的是抢占式调度

线程调度可以通过设置线程的优先级来给操作系统建议,Java 中线程优先级有十种。但是线程调度最终还是操作系统决定。因为:

  • 操作系统的优先级数目可能比 Java 中的线程优先级数目少,如 Windows 中就只有 7 种,所以 Java 中不同的优先级可能对应到相同的操作系统优先级。
  • 优先级可能会被系统自动改变。

0.5 线程同步

线程同步指多个线程访问同一个资源应该互斥访问。当有一个线程正在访问该资源时,其他线程都应等待,直到该线程访问结束。


文章作者: Yu Yang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Yu Yang !
 上一篇
AQS AQS
11. AQSAQS,AbstractQueuedSynchronizer,抽象队列同步器,是一个抽象类。 是用来构建锁和同步器的框架。基于 AQS 实现的锁: ReentrantLock ReentrantReadWriteLock C
下一篇 
1.Java 中多线程的实现 1.Java 中多线程的实现
1. Java 中多线程的实现主要有三种方案: 继承 Thread 类,并重写 run() 方法 实现 Runnable 接口,并重写 run() 方法 实现 Callable 接口,并重写 call() 方法 其中前两种比较常见。 1
  目录