iOS 多线程的概念、原理

图1.png

线程和进程的关系和区别

线程定义
  • 线程是进程的基本执行单元,一个进程的所有任务都在线程中执行
  • 进程要想执行任务,必须得有线程,进程至少要有一条线程
  • 程序启动会默认开启一条线程,这条线程被称为主线程或 UI 线程
进程定义
  • 进程是指在系统中正在运行的一个应用程序
  • 每个进程之间是独立的,每个进程均运行在其专用的且受保护的内存空间内
  • 通过“活动监视器”可以查看 Mac 系统中所开启的进程
进程与线程的区别
  • 地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间。
  • 资源拥有:同一进程内的线程共享本进程的资源如内存、I/O、cpu等,但是进程之间的资源是独立的。
  • 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
  • 进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程
  • 执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
  • 线程是处理器调度的基本单位,但是进程不是。

多线程的意义

优点

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

缺点

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


    图2.png

好像主线程也是512KB,而不是1MB

多线程的原理
图3.png
多线程的生命周期
图4.png
  • 新建线程,执行start,线程必须start,否则没有作用。但也不可以重复start,会导致崩溃
  • 线程start后,将会进入Runnable状态。
  • 进入Runnable状态后,进入Running状态,当前线程会被CPU调度。也有可能在进入Running状态后,线程切换,返回Runnable状态

CPU如何调度线程?线程池的原理

图5-线程池参数.png

图6-线程池的原理.png

1.系统有一个可调度线程池,如果线程池里有这个线程,就会开始执行。
2.如果没有,将判断线程池大小是否小于核心线程池大小,如果小于,那将会开辟新的线程来执行任务。
3.如果大于线程池,代表线程池没有能力再去开辟新的线程,只能依赖于原有的线程去执行 ,就将判断工作队列是否已满,如果没满就将任务提交到工作队列,等待执行任务。
4.满了的话,线程池就会判断所有线程是否都在工作,如果有空闲的线程,就让这条线程去执行任务。
5.如果还是没有空闲的线程,就将任务交给饱和策略
6.饱和策略分为四种

Abort策略:默认策略,新任务提交时直接抛出未检查的异常RejectedExecutionException,该异常可由调用者捕获。
CallerRuns策略:为调节机制,既不抛弃任务也不抛出异常,而是将某些任务回退到调用者。不会在线程池的线程中执行新的任务,而是在调用exector的线程中运行新的任务。
Discard策略:新提交的任务被抛弃。
DiscardOldest策略:队列的是“队头”的任务,然后尝试提交新的任务。(不适合工作队列为优先队列场景)

  • Running后,有可能任务会造成堵塞,当造成堵塞的任务执行结束后,同样会回到Runnable状态,继续执行Running
  • 死亡,分为任务执行结束跟强制退出线程exit

线程操作

查看NSThread相关文件可以看到,线程有多种状态,可以根据不同情况,判断线程的状态,来做不同的操作。可通过重写下面的方法掌握线程的生命周期(YYKit)。
一般情况下,我们很少去中止一个网络请求,按照一般的情况,是没办法中止的,但是依靠线程,通过关闭线程,从而达到中止网络请求的目的。

@property (readonly, getter=isExecuting) BOOL executing API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property (readonly, getter=isFinished) BOOL finished API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property (readonly, getter=isCancelled) BOOL cancelled API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

- (void)cancel API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)start API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)main API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)); // thread body method

线程安全

这是一张经典的多线程比喻图。多端增删改查。


图7.png

如何避免上图的情况?如何保证线程安全?
上锁

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 进程和线程 进程 所有运行中的任务通常对应一个进程,当一个程序进入内存运行时,即变成一个进程.进程是处于运行过程中...
    胜浩_ae28阅读 10,573评论 0 23
  •   一个任务通常就是一个程序,每个运行中的程序就是一个进程。当一个程序运行时,内部可能包含了多个顺序执行流,每个顺...
    OmaiMoon阅读 5,688评论 0 12
  • 又来到了一个老生常谈的问题,应用层软件开发的程序员要不要了解和深入学习操作系统呢? 今天就这个问题开始,来谈谈操...
    tangsl阅读 9,669评论 0 23
  • 进程和线程 进程 所有运行中的任务通常对应一个进程,当一个程序进入内存运行时,即变成一个进程.进程是处于运行过程中...
    小徐andorid阅读 7,929评论 3 53
  • 出来工作,每个人都是为了更好的发展。在公司中我们总是期望着升职加薪,如果自身得不到发展,那么就免不了跳槽。 不过,...
    秋风_bdfd阅读 1,175评论 0 0

友情链接更多精彩内容