概述
首先明确几个概念
- 队列:队列分为串行和并行。串行队列按照A、B、C、D的顺序添加四个任务,这四个任务按照顺序执行,结束顺序也肯定是A、B、C、D,而并行队列同时执行这四个任务,完成的顺序因此也是随机的。
- 异步执行(async)和同步执行(sync):使用dispatch_async调用一个block,这个block会被放到指定的queue_1队列尾等待执行,至于这个block是被并行还是串行执行,只和dispatch_async中的指定的queue_1有关,但是dispatch_async会马上返回。使用dispatch_sync同样也是把block放到指定的queue_2上执行,但是会等待这个block执行完毕后才返回,这期间会阻塞当前运行调用dispatch_async或dispatch_sync代码的queue(通常为main_queue)直到sync函数返回。
以打电话给查号台为例:
- 同步:打电话给查号台,问某个地方的电话号码,接线员会告诉你稍等,然后为你查号,此时你的电话没有挂断,其他的电话也不能打进来,等到接线员查找到了你要找的电话号,告诉你后,才将电话挂断
- 异步:打电话给查号台,问某个地方的电话号码,接线员知道了你的请求后,会立刻挂断电话,此时其他的电话可以打进来。然后开始为你查号。等到查找到了你要找的电话号,会再打电话通知你。
示例
异步
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"async:1");
});
NSLog(@"async:2");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"async:3");
});
NSLog(@"async:4");
结果为
async:2
async:4
async:1
async:3
可以看出,dispatch_async将block追加到线程中后,并未等待,立刻执行后面的代码
同步
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"sync:1");
});
NSLog(@"sync:2");
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"sync:3");
});
NSLog(@"sync:4");
结果为
sync:1
sync:2
sync:3
sync:4
可以看出,dispatch_sync将block追加到线程中后,等待block执行完毕后才接着执行后面的代码
死锁
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"mainQueue_sync:1");
});
上述代码会造成死锁。原因:main_queue为串行队列,在当前queue上调用sync函数,sync指定的queue也是当前queue。需要执行的block被放到当前queue的队尾等待被执行,因为这是一个串行的queue,调用sync函数会阻塞当前队列,等待block被执行->这个block一直不会被执行->sync函数一直不返回,所以当前queue就被阻塞了,造成了死锁。
说明
开发者要做的只是定义想执行的任务并追加到适当的Dispatch Queue中。
上述引用自苹果官方对GCD的说明,因此Dispatch_async和Dispatch_sync的作用是将block追加到队列中。这句话对于上述理解死锁有很大帮助。
实例
print(1)
serialQueue.async {
print(2)
serialQueue.sync {
print(3)
}
print(4)
}
print(5)
分析:只会打印1,2,然后就死锁了。原因是列serialQueue.async
的block1被异步追加到串行队列上后,开始执行,这个block1中又被同步追加了一个block2,此时serialQueue被阻塞,等待block2执行完毕,但是block1还未执行完毕,由于是串行队列,block只能按照追加的先后顺序一个一个执行:线程被阻塞->block1停止执行->block2等block1执行完毕->因此就造成了死锁。
网友评论