Skip to content

并发编程

基本概念

  • 进程:进程是操作系统进行资源分配和调度的基本单位
    • 每个进程都有独立的地址空间,一个进程无法直接访问另一个进程的资源和数据
    • 进程间相互隔离,提供了良好的安全性。
    • 进程间通信(IPC)相对复杂,开销较大。
    • 适合大规模、独立的应用程序,需要强隔离或分布在不同机器上。
  • 线程:操作系统能够进行运算调度最小单位,是进程中的实际运作单位。一个进程可以包含多个线程
    • 线程间共享进程资源,易于通信和数据共享。
    • 相比进程,线程的创建和上下文切换开销更小。
    • 适合需要并发执行多个任务的应用,如服务器、GUI应用等。
    • 共享进程的地址空间和资源,但每个线程有自己的执行序列、栈空间和程序计数器。
  • 协程:用户态的轻量级线程,它的调度完全由用户控制。
    • 协程切换开销极小,因为所有的切换都在用户态完成,无需陷入内核态。
    • 协程可以用同步的方式编写异步代码,简化了异步编程模型。
    • 与线程类似,协程也共享所在进程的资源,但它们更轻量,能创建成千上万的实例。
    • 适合 IO 密集型任务、并发编程,如 Web 服务器、网络爬虫等。
  • 协程主要用于需要异步执行但是不涉及密集计算的场景,如延时、IO、异步加载等

  • 多线程适用于密集型计算或可以并行执行的任务,特别是可能阻塞主线程的任务

  • 协程通过在单个线程内部进行任务切换来实现并发,而不是依赖操作系统的线程调度。

    • 协程通常运行在一个事件循环内。事件循环负责调度和管理所有的协程,以及处理 IO 事件、定时器事件等。
    • 协程非常适合处理异步 IO 操作,因为它们可以在等待 IO 操作完成时挂起,让出 CPU 给其他协程使用,从而提高程序的整体效率。
    • 理论上避免了多线程并发中的数据竞争和锁问题
  • 线程之间共享哪些资源,不共享那些资源:

    • 共享:代码段、数据段、堆内存、信号和信号处理器、进程打开的文件描述符和其他资源
    • 不共享:线程栈、线程上下文、线程特定数据
  • 进程间通讯方式

    • 匿名管道:允许有血缘关系的进程(如父子进程)进行双向通信,但通常用于单向通信。数据流动类似于水流,一端输入,另一端输出。(创建两个管道来实现全双工)
      • 父进程创建两个匿名管道,管道 1(fd1[0]和 fd1[1])和管道 2(fd2[0] 和 fd2[1]);
      • 父进程 fork 出子进程,于是对于这两个匿名管道,子进程也分别有两个文件描述符指向匿名管道的读写两端;关闭部分端口
      • 管道的本质就是内核在内存中开辟了一个缓冲区,这个缓冲区与管道文件相关联,对管道文件的操作,被内核转换成对这块缓冲区的操作。
      • image.png|375
    • 有名管道:与匿名管道类似,但它们在文件系统中有一个名字,可以在任何没有直接关系的进程间进行通信。
    • 套接字
    • 信号:通知事件发生,不能携带大量数据
    • 消息队列:消息队列允许不同进程读写一个队列,实现复杂的通信。每个消息都是一个数据块,包含了消息类型和数据本身,进程可以异步地交换消息。
      • 两个队列或一个(约定收发消息的格式)
      • 管道连续数据,消息队列是以消息为单位
      • 消息队列更加灵活,如优先级消息
    • 共享内存
    • 信号量
  • 线程间通讯方式

    • 共享内存
    • 信号量(pv 操作):通过信号量实现线程间同步
      • 信号量内部的计数器表示当前可用的资源数量。计数器的初始值通常表示共享资源的总数量。
      • wait() 操作p:线程调用 wait() 时,信号量的计数器会减一。如果计数器的值在减一之前就是零,则调用 wait() 的线程将被阻塞,直到计数器大于零。这个操作有时也被称为 P 操作。
      • signal() 操作v:线程完成对共享资源的使用后,调用 signal() 使信号量的计数器加一。如果有线程因为调用 wait() 而被阻塞,这时它们中的一个将被唤醒。这个操作有时也被称为 V 操作。
      • 用途:当信号量的计数器初始化为1时,它可以作为一个互斥锁;信号量也用于限制对一组资源的同时访问。
    • 条件变量(wait(), notify(), 和 notifyAll()
    • 消息队列
  • 线程的状态:

  • 新建状态:已经被创建,但是尚未执行,如java中创建了Thread对象,但是没有start

  • 就绪状态:已经准备好运行并等待CPU时间片(可运行,正等待操作系统调度)
  • 运行状态:线程正在执行,操作系统分配给线程CPU时间片之后,就从就绪状态变成了运行状态
  • 阻塞状态:线程因为某些原因放弃CPU使用权,主动进入等待。(等待阻塞wait、同步阻塞等待锁、其他阻塞sleep、io)

  • 等待状态:等待其他线程做出特定动作,通常发生在线程间协作

  • 超时等待:有最大等待时间,超时后返回
  • 终止状态:运行一节结束(执行完成或者出现错误),不能重新启动

  • 安卓中进程间通信方式

  • intent活动间传递数据(启动的同时)
  • binder:一个进程获取另一个进程的引用,如service绑定
  • contentprovider:不同应用之间共享数据的标准API
  • BroadcastReceivers:接受系统级或应用级广播消息
  • 消息队列和Handler
  • 共享文件如SharedPreferences
  • Socket(网络)