美文网首页
OC底层原理19 - 多线程基本概念

OC底层原理19 - 多线程基本概念

作者: 卡布奇诺_95d2 | 来源:发表于2021-04-01 17:43 被阅读0次

线程与进程

线程与进程概念

  • 进程是指在系统中正在运行的一个应用程序
  • 线程进程基本执行单元,一个进程的所有任务都在线程中执行。
  • 进程至少要有一条线程
  • 程序启动会默认开启一条线程,这条线程被称为主线程或者UI线程
  • 进程之间是独立的,每个进程均运行在其专用的且受保护的内存空间内。

进程与线程的关系

  1. 进程与线程是包含与被包含的关系,即:进程中包含多个线程
  2. 同一个进程中的线程共享进程的地址空间和资源
  3. 多进程比多线程健壮。即一个进程崩溃之后一般情况下不会对其它进程产生影响,但是一个线程崩溃了,那整个进程都无法继续了。
  4. CPU调度的基本单位是线程
  5. 各进程进行切换时,会消耗一定的资源,如果频繁切换进程,效率较低下。
  6. 线程不能独立执行,必须依存于应用程序中。

线程和Runloop的关系

  1. runloop与线程是一一对应的,一个runloop对应一个线程。
  2. runloop是来管理线程的,当线程的runloop被开启后,线程会在执行完任务后进入休眠状态,有了任务就会被唤醒去执行任务。
  3. runloop在第一次获取时被创建,在线程结束时被销毁
  4. 对于主线程来说,runloop在程序一启动就默认创建好了
  5. 对于子线程来说,runloop是懒加载的,只有当我们使用的时候才会创建,所以在子线程用定时器要注意:确保子线程的runloop被创建,不然定时器不会回调

多线程原理

多线程原理

对于单核CPU,同一时间,CPU只能处理一条线程,即只有一条线程在工作,这种情况下的多线程的本质是CPU在多个任务之间进行快速的切换,由于CPU调度线程的时间足够快,就造成了多线程的“同时”执行的效果。其中切换的时间间隔就是时间片。
对于多核CPU,同一个时间,CPU可以处理多条线程。

多线程意义

优点:

  • 能适当提高程序的执行效率
  • 能适当提高资源的利用率,如CPU、内存
  • 线程上的任务执行完成后,线程会自动销毁

缺点:

  • 开启线程需要占用一定的内存空间,默认情况下,每一个线程占用512KB
  • 线程越多,CPU在调用线程上的开销就越大
  • 程序设计更加复杂,比如线程间的通信,多线程的数据共享

多线程生命周期

多线程的生命周期有5个状态:

  • 新建:创建一个线程,主要是实例化线程对象。
  • 就绪:线程对象调用start方法,将线程对象加入可调度线程池,等待CPU的调用。即调用start方法,并不会立即执行,进入就绪状态,需要等待一段时间,经CPU调度后才执行,也就是从就绪状态进入运行状态。
  • 运行:CPU负责调度可调度线程池中线程的执行,在线程执行完成之前,其状态可能会在就绪和运行之间来回切换,这个变化是由CPU负责,开发人员不能干预。
  • 阻塞:当满足某个预定条件时,如sleep或者同步锁,这些会阻塞线程执行。当进入sleep时,会重新将线程置为就绪状态。
  • 死亡:分为两种情况:
    • 情况1:正常死亡,即线程执行完毕。
    • 情况2:非正常死亡,即当满足某个条件后,在线程内部(或者主线程中)终止执行(调用exit方法等退出)
多线程生命周期.png

线程池原理

线程池原理.png
  • 【第一步】判断核心线程池中是否已满
    如果已经满了,进入【第二步】。
    如果未满,则创建新的线程执行任务。

  • 【第二步】判断线程池工作队列是否已经满
    如果已经满了,进入【第三步】。
    如果未满,则将任务存储到工作队列中,等待CPU的调度。

  • 【第三步】判断线程池中的线程是否都处于执行状态
    如果是,进入【第四步】。
    如果不是,则安排可调度线程池中空闲的线程去执行任务

  • 【第四步】交给饱和策略去执行,主要有以下四种(在iOS中并没有找到以下4种策略)
    AbortPolicy:直接抛出RejectedExecutionExeception异常来阻止系统正常运行
    CallerRunsPolicy:将任务回退到调用者
    DisOldestPolicy:丢掉等待最久的任务
    DisCardPolicy:直接丢弃任务

iOS中多线程的实现方案

方案 简介 语言 线程生命周期 使用频率
pthread 1、一套能用的多线程API;
2、适用于Linux、Unix、Windows等系统;
3、跨平台、可移植;
4、使用难度较大
C 程序员管理 几乎不用
NSThread 1、使用更加面向对象;
2、使用较为简单,可直接操作线程对象;
OC 程序员管理 偶尔使用
GCD 1、替代NSThread等线程技术;
2、充分利用设备的多核;
C 自动管理 经常使用
NSOperation 1、基于GCD封装;
2、比GCD多了一些更加简单实用的功能;
3、使用更加面向对象;
OC 自动管理 经常使用

在iOS的多线程使用过程中,存在C和OC的桥接,则需要注意的点如下:

  • __bridge只做类型转换,但是不修改对象(内存)管理权

  • __bridge_retained(也可以使用CFBridgingRetain)将Objective-C的对象转换为 Core Foundation的对象,同时将对象(内存)的管理权交给我们,后续需要使用 CFRelease或者相关方法来释放对象

  • __bridge_transfer(也可以使用CFBridgingRelease)将Core Foundation的对象 转换为Objective-C的对象,同时将对象(内存)的管理权交给ARC。

线程安全问题

当多个线程同时访问同一块资源时,容易引发数据错乱和数据安全问题,目前主要有以下两种解决方案

  • 互斥锁(即同步锁):@synchronized
  • 自旋锁

互斥锁

作用:确保同一时间,只有一条线程能够执行

  • 如果代码中只有一个地方需要加锁,大多都使用self,这样可以避免单独再创建一个锁对象

  • 加了互斥锁的代码,当新线程访问时,如果发现其他线程正在执行锁定的代码,新线程就会进入休眠状态

  • 互斥锁的锁定范围,应该尽量小,锁定范围越大,效率越差

  • 互斥锁能够加锁任意 NSObject 对象

  • 锁对象一定要保证所有的线程都能够访问

自旋锁

自旋锁与互斥锁类似,但它不是通过休眠使线程阻塞,而是在获取锁之前一直处于忙等(即原地打转,称为自旋)阻塞状态。

使用场景:锁持有的时间短,且线程不希望在重新调度上花太多成本时,就需要使用自旋锁,属性修饰符atomic,就有一把自旋锁。

加入了自旋锁,当新线程访问代码时,如果发现有其他线程正在锁定代码,新线程会一直等待锁定的代码执行完成,即不停的尝试执行代码,比较消耗性能。

atomic 原子锁 & nonatomic 非原子锁

atomicnonatomic主要用于属性的修饰。

  • atomic是原子属性,是为多线程开发准备的,是默认属性。它会在属性的setter方法中,增加锁(自旋锁),保证同一时间,只有一条线程对属性进行写操作,但同一时间,可以多条线程对属性进行读操作,它在Mac开发中较为常用。
  • nonatomic是非原子属性。它不会增加锁,因此性能较高,它在移动端开发较为常用。

相关文章

网友评论

      本文标题:OC底层原理19 - 多线程基本概念

      本文链接:https://www.haomeiwen.com/subject/dfhhhltx.html