谈谈dispatch_sync 和 dispatch_async

看了网上很多关于多线程介绍这俩货的,夹杂着串行队列,并发队列,主队列,全局队列,开/不开新线程,看的我是头都晕了.得,我干脆自己也整一篇,梳理一下.

dispatch_sync,往一个派发队列上提交一个同步执行的Block,阻塞当前线程.不开新线程.
dispatch_async,往一个派发队列上提交一个异步执行的Block,不阻塞当前线程.可能会开新线程.

接下来详细说一下这两个函数:
dispatch_sync提交的Block是几乎是在当前线程执行的(注意是当前线程),也就是说在哪个线程调用的这个方法,那么该Block就在哪个线程上执行,唯一的一个例外就是如果在子线程中调用并提交到主队列则block是在主线程执行.就是这么回事,在文档上那也是写的明明白白.所以该方法不会新开线程.又因为是同步执行Block,也就是说要等到Block执行完后该方法才会返回,所以会阻塞当前线程.这意味着什么?意味着如果你提交的队列就是当前线程所属的队列,那么将导致死锁,崩溃.
图示如下:

死锁.png

解释如下:
任务A要想执行完,则必须要等待dispatch_sync函数返回,
然而dispatch_sync要想返回又必须等待任务B完成,
队列又是先进先出的,所以任务B要想执行则必须等待任务A执行完成,
这就形成了相互等待,从而发生死锁.
有些人可能会想凭啥任务B就得排在任务A后面?咋就不能在任务A前面?
我现在就告诉你还真不能,前面已经说了dispatch_sync是不新开线程的,它
现在在当前线程提交一个任务B,那理所当然的任务B就得排在任务A后面.

代码如下,你在主线程中这么写就会导致死锁.

dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"---%@--", [NSThread currentThread]);
});

再来说说dispatch_async,上面说可能会新开线程.那到底啥时候开,啥时候不开呢?
相信很多人都在主线程写过这样的代码:

dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"---%@--", [NSThread currentThread]);
});

打印很明显还是主线程,它没有新开线程.而打印日志会在稍后某个时间打印.有人可能又想问为啥这里又不死锁呢?那是因为dispatch_async提交Block后并不等待Block执行完成而是马上返回,结束调用了,它没有阻塞当前线程.

现在你可能已经明白了,对于dispatch_async,如果你在线程所属的队列使用dispatch_async提交一个Block到该队列,那么它就不会新开线程,否则它就会新开一个线程.

举个例子:假如你现在在主线程,也就是在主队列里,此时你dispatch_async一个Block到全局队列,或自己创建的串行/并发队列,那么它将新开线程执行该Block.

完了.