底层20:多线程-同步/异步/并发/串行
GCD两种常用的函数:
GCD中有2个用来执行任务的函数
用同步的方式执行任务:dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
queue:队列
block:任务
用异步的方式执行任务:dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
GCD是开源的:https://github.com/apple/swift-corelibs-libdispatch
GCD队列:
并发队列(Concurrent Dispatch Queue):
可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务);
并发功能只有在异步函数下才有效。
串行队列:让任务一个接着一个地执行(一个任务执行完后,再执行下一个任务)
容易混淆的术语:
有4个术语比较容易混淆:同步、异步、并发、串行
同步和异步主要影响:能不能开启新的线程
同步:在当前线程中执行任务,不具备开启新线程的能力。
异步:在新的线程中执行任务,具备开启新线程的能力
并发和串行主要影响:任务的执行方式
并发:多个任务并发(同时)执行
串行:一个任务执行完毕以后,再执行下一个任务(主队列也是一个串行队列)
各种队列的执行效果
死锁实例分析
实例1:
分析:是在主队列中执行,因为是同步并且在viewDidLoad方法中,所以在是在主线程中执行,队列存在先进先出的原则,首先要执行完viewDidLoad方法才能执行任务2,但是任务2又在viewDidLoad方法中,相当于任务2和3相互等待造成死锁。
实例2:
分析:因为在主线程中执行,是串行队列串行执行任务,而异步刚好不要求立马在当前线程同步执行任务,所以打印顺序:执行任务1、执行任务3、执行任务2
实例3:
分析:发现任务3和任务4跟实例1一样。
实例4: 如下只要创建了第二个队列替换,不管是串行还是并发 都不会产生死锁
实例5: 换成并发队列,任务3,4不会等待,并发执行。
总结:使用 sync函数 往 当前串行队列 中添加任务,会卡住当前的串行队列(产生死锁)
分析:全局队列打印地址一样,说明全局队列始终是同一个队列(也可以理解为全局队列相当于是一个全局变量,始终是同一个);后面自行创建的并发队列,地址不一样,说明是不同的队列。
注意:
[self performSelector:@selector(test) withObject:nil afterDelay:.0];的本质是往RunLoop中添加定时器,而子线程默认没有启动runLoop。所以需要手动启动:
[self performSelector:@selector(test) withObject:nil]跟它是不一样的,没有关系到RunLoop,如果它不启动照常打印。