《新浪微博剖析 iOS 高级面试》笔记(六):多线程相关面试问题
GCD
1、同步/异步 & 串行/并发
a、同步串行
b、死锁原因
- 死锁是因为队列引起的循环等待,而非线程。
- 首先在
主线程
执行主队列
中的viewDidLoad
函数。 - 当执行到
block
时,因为是同步
,所以需要hold住主线程
中主队列
正在执行的viewDidLoad
函数,等执行完主队列
中block
内部代码后,再执行主线程
中主队列
的viewDidLoad
函数。 - 所以出现了
viewDidLoad
等待block
的情况。 block
内的代码要执行,必须等待队列中其他函数执行完,即先进先出
。- 所以出现了
block
等待viewDidLoad
的情况。 - 最终两个函数
相互等待
,出现造成死锁
。
- 首先在
- 上面这种用法没问题
- 首先在
主线程
执行主队列
中的viewDidLoad
函数。 - 当执行到
block
时,因为是同步
,所以需要hold住主线程
中主队列
正在执行的viewDidLoad
函数,等执行完主队列
中block
内部代码后,再执行主线程
中主队列
的viewDidLoad
函数。 - 所以出现了
viewDidLoad
等待block
的情况。 block
内部的代码会在serialQueue
的队列中取出,因为serialQueue
中block
排在最前,所以block
会被立即取出,并在主线程
中执行。- 待
block
执行完毕,会执行viewDidLoad
剩余代码。
- 首先在
- 因为是
并发队列
,所以运行队列中的任务一起执行,不需要等待上一个任务执行完再执行下一个,所以不会死锁
。 - 如果
global_queue
换成串行队列
,就会产生死锁
。
c、异步串行
- 先执行完
viewDidLoad
,再执行block
内的代码。 - 因为子线程默认没有开启
runloop
,performSelector
无法执行。
2、dispatch_barrier_async
a、怎样利用GCD实现多读单写?
- 读的时候使用
dispatch_sync
,是因为使用同步队列
可以在赋值结束后,再执行返回值的操作。
3、dispatch_group
a、使用GCD实现A、B、C三个任务并发,完成后执行任务D。
NSOperation
1、优势、特点
- 添加任务依赖
- 任务执行状态控制
- 最大并发量
2、任务状态
isReady
isExecuting
isFinished
isCancelled
3、任务状态控制
- 如果只重写
main
方法,底层控制变更任务执行完成状态,以及任务退出。 - 如果重写了
start
方法,自行控制任务状态。
a、系统是怎样移除一个isFinished=YES
的NSOperation
的?
- KVO
NSThread
1、NSThread启动流程
多线程与锁
- os_unfair_lock
- OSSpinLock
- 循环等待询问,不释放当前资源
- 用于轻量级数据访问,简单的int值 +1/-1操作
- dispatch_semaphore
- pthread_mutex
- dispatch_queue(DISPATCH_QUEUE_SERIAL)
- NSLock
- NSCondition
- pthread_mutex(recursive)
- NSRecursiveLock
- NSConditionLock
- @synchronized
- 一般在创建单例对象的时候使用,保证在多线程环境下,创建是唯一的。
1、NSLock死锁问题
- 可以使用
NSRecursiveLock递归锁
来解决该问题。
多线程面试问题总结
- 怎样用
GCD
实现多读单写? - iOS系统为我们提供的几种多线程技术各自的特点是怎样的?
AFNetworking
&SDWebImage
使用NSOperation
,因为可以控制线程状态。
- 系统是怎样移除一个
isFinished=YES
的NSOperation
的? - 你都用过哪些锁?结合实际谈谈你是怎样使用的?
转载自:https://juejin.cn/post/6901562047965134861