在 GCD 中,加入了两个非常重要的概念:任务和队列
一个线程是可以拥有多个执行队列的,所有任务是添加到队列中等待执行的
主队列是特殊的串行队列,自己创建的队列可以指定串行或并行,全局队列是并行队列
任务:即操作,你想要干什么,说白了就是一段代码,在 GCD 中就是一个 Block,所以添加任务十分方便。
任务有两种执行方式: 同步执行和异步执行,他们之间的区别主要在于会不会阻塞当前线程
首先看下面这两个例子:
1、
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); dispatch_sync(queue, ^{ NSLog(@"%d",[[NSThread currentThread] isMainThread]); });
2、
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); dispatch_async(queue, ^{ NSLog(@"%d",[[NSThread currentThread] isMainThread]); });
两个例子都是创建一个新队列,之间的区别只在于前者是以同步运行,后者则是异步
结果前者打印出1,后者则是0。
我们分析一下,这里同步的意思其实是对于线程的所有执行队列而言,就是说同步执行时,除了block任务,在同一个线程执行的其他队列全部暂停执行,当block任务执行完成后,其他队列任务才恢复执行。(这里还有个要特别注意的,就是系统在判别是否要暂停队列的执行时,是按照block任务是否在队列头,如果不是就停止队列执行)
上面例子1中创建一个新队列,block任务在第一个,即队列头,以同步执行时就是所有在主线程执行的队列会暂停执行(除了block任务所在队列)。例子2因为是创建一个新队列,又是异步执行,所以会创建一个新线程执行,所以打印出来的0,也就是主线程上的队列照常执行。
为了证明我上面的假设,我举个例子:
3、
dispatch_queue_t queue = dispatch_get_main_queue(); dispatch_sync(queue, ^{ NSLog(@"%d",[[NSThread currentThread] isMainThread]); });
4、
dispatch_queue_t queue = dispatch_get_main_queue(); dispatch_async(queue, ^{ NSLog(@"%d",[[NSThread currentThread] isMainThread]); });
上面两个例子都是将block任务添加到主队列,但是结果却不同,例子3结果是永远不会执行打印语句,程序不会再执行了,例子4正常执行,且在主队列中
结论:不是异步就一定会开启新的线程
例子3因为将block任务添加到主队列中,此时主队列还有任务(viewDidLoad没有执行完,所以block任务不是将要执行的任务),根据前面的系统判定,主队列被暂停执行,此时前面的任务无法完成,后面的block任务也无法完成,造成死循环
例子4中将任务添加到主队列中,虽然是异步操作,但是并不会开启新的线程,因为在主队列中,要在主线程中执行,而异步操作不会将线程阻塞,所以队列照常执行。
结论:同步会让系统判定暂停执行所有不以block块任务为第一任务的队列(即如果block块任务不在队列头,那么block块任务所在的队列也会暂停执行),且同步一定不会开启新线程,因为GCD觉得既然其它队列暂停执行,block块任务就可以在当前线程执行了,没有必要开启新线程。而异步则系统不会进行判定,但是不一定会开启新线程,这个跟队列有关,如果是新创建的队列,那么GCD就会开启新线程,如果加入已有的队列,那么就会在队列所在的线程中执行。
简单来讲,同步操作那么block块任务会在当前线程中执行,比如上面在主线程中进行同步操作,那么一定就是在主线程中执行,不管队列是主队列还是全局队列或者自己创建的队列。如果是异步操作的话,那么就要分情况来看了,如果是主队列,那么就是在主线程中执行,如果是全局或自己创建的队列,那么就是在新创建的线程中执行,全局队列会根据任务自动创建一个或多个线程,自己创建的队列就是根据参数设定和任务进行分配。
至于串行和并行,串行和并行是针对同一个队列中的任务而言的,当使用串行,那么队列里的那么队列里的任务最多只能使用一个线程运行,即同一时刻只有一个任务在执行,如果是并行,那么系统会根据队列里的任务自动分配线程执行,最大线程数根据参数设定
转载请注明:作者SmithJackyson