likes
comments
collection
share

iOS 多线程概念回顾

作者站长头像
站长
· 阅读数 26

线程与进程

线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。

进程: 每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)

线程: 同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)

多线程

多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。

优点

  • 使用线程可以把占据时间长的程序中的任务放到后台去处理
  • 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
  • 程序的运行速度可能加快
  • 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下可以释放一些珍贵的资源如内存占用等

缺点

  • 如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换
  • 更多的线程需要更多的内存空间
  • 线程可能会给程序带来更多“bug”,因此要小心使用
  • 线程的中止需要考虑其对程序运行的影响
  • 通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生

线程的生命周期

iOS 多线程概念回顾

生命周期的五种状态

  • 新建:实例化线程对象

  • 就绪:向线程对象发送start消息,线程对象被加入可调度线程池等待CPU调度。

  • 运行:CPU 负责调度可调度线程池中线程的执行。线程执行完成之前,状态可能会在就绪和运行之间来回切换。就绪和运行之间的状态变化由CPU负责,程序员不能干预。

  • 阻塞:当满足某个预定条件时,可以使用休眠或锁,阻塞线程执行。sleepForTimeInterval(休眠指定时长),sleepUntilDate(休眠到指定日期),@synchronized(self):(互斥锁)。

  • 死亡:正常死亡,线程执行完毕。非正常死亡,当满足某个条件后,在线程内部中止执行/在主线程中止线程对象

  • 还有线程的exitcancel

  • [NSThread exit]:一旦强行终止线程,后续的所有代码都不会被执行。

  • [thread cancel]取消:并不会直接取消线程,只是给线程对象添加isCancelled 标记。

iOS的多线程实现方式

iOS 多线程概念回顾

线程池的调度

iOS 多线程概念回顾

饱和策略

当任务提交线程池失败时,即当前提交的任务数超过maxmumPoolSizeworkQueue之和时,就会交给饱和策略处理。 饱和策略有四种,AbortPolicyCallerRunsPolicyDiscardPolicyDiscardOldestPolicy

  • AbortPolicy 中止策略,属于默认的饱和策略,该策略将抛出未检查的RejectedExecutionException。调用者可以捕获这个异常,然后根据需要编写自己的处理代码。
  • DiscardPolicy 抛弃策略,当新提交的任务无法保存到队列中等待执行时,"抛弃(Discard)"策略会悄悄抛弃该任务。
  • DiscardOldestPolicy 抛弃下一个将被执行的任务,然后尝试重新提交新的任务。(如果工作队列是一个优先队列,那么"抛弃最旧的"策略将导致抛弃优先级最高的任务,因此最好不要将"抛弃最旧的"饱和策略和优先队列放在一起使用。)
  • CallerRunsPolicy 调用者策略,策略实现了一种调度机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量。它不会在线程池的某个线程中执行新提交的任务,而是在一个调用了execute的线程中执行该任务。如果采用有界队列和"调用者运行"饱和策略,当线程池中的所有线程都被占用,并且工作队列被填满后,下一个任务会在调用execute时在主线程中执行。由于执行任务需要一定的时间,因此主线程至少在一段时间内不能提交任何任务,从而使得工作者线程有时间来处理完正在执行的任务。在此期间,主线程不会调用accept,因此到达的请求将被保存在TCP层的队列中而不是在应用程序的队列中。如果持续过载,那么TCP层将最终发现它的请求队列被填满,因此同样会开始抛弃请求。当服务器过载时,这种过载情况会逐渐向外蔓延开来——从线程池到工作队列到应用程序再到TCP层,最终达到客户端,导致服务器在高负载下实现一种平缓的性能降低。

以上四种拒绝策略均实现的RejectedExecutionHandler接口。

相关面试题

任务的执行速度受什么因素影响?

  • cpu   
  • 任务的复杂度  
  • 优先级  
  • 线程的状态

个人理解:银行的柜台  1.有几个柜台开了,服务员工作效率高不高  2.当前柜台这个工作麻烦不麻烦 3.有没vip客户  4.当几个柜台都有人的时候,大堂经理有没做人员分配的调度.

自旋锁与互斥锁

自旋锁:atomic、OSSpinLock、dispatch_semaphore_t 互斥锁:pthread_mutex、@ synchronized、NSLock、NSConditionLock 、NSCondition、NSRecursiveLock

  • 自旋锁   发现其他线程执行   当前线程 休眠(就绪状态) 一直等待打开唤醒执行
  • 互斥锁   发现其他线程执行   当前线程 询问(忙等) 耗费性能比较高

atomicnonatomic

atomic

  • 是默认的
  • 对同一对象的set和get的操作是顺序执行的
  • 速度不快,因为要保证操作整体完成
  • 线程安全,需要消耗大量系统资源来为属性加锁 使用atomic并不能保证绝对的线程安全,对于要绝对保证线程安全的操作,还需要使用更高级的方式来处理,比如NSSpinLock@syncronized

nonatomic

  • 不是默认的
  • 更快
  • 如有两个线程访问同一个属性,会出现无法预料的结果
  • 非线程安全,适合内存较小的移动设备
转载自:https://juejin.cn/post/6993274695508295716
评论
请登录