案例1 中 在主队列(主队列也是一个串行队列)中同步添加block任务,导致主线程等待dispatch_sync函数执行完后处理block,而block等待主线程执行dispatch_sync函数结束,函数结束又需要block执行结束,导致相互等待,产生死锁.
案例2 中,另外开了一个串行队列,与主队列不是相同的串行队列,不会产生相互等待对方,因此不会死锁.
前面讲过,在某一个串行队列中,同步的向这个队列添加任务会产生死锁,案列3 就是在myqueu这个串行队列中同步添加任务3,导致死锁.
异步 dispatch_async,或者 使用不相同的串行队列.
死锁,崩溃。
原因: 主队列在执行viewDidLoad任务,又同步执行block任务;
viewDidLoad任务等待block任务结束;block任务又在等待viewDidLoad任务。
造成主队列的相互等待,并非主线程死锁。
死锁,崩溃。原因与在主线程同步提交主队列原因相同。由于串行队列的相互等待造成死锁。
队列改成并发,可以正常执行。
上层业务异步获取结果再调同步也会死锁。
概念:队列只负责任务的调度,而不负责任务的执行,任务是在线程中执行的。(可以理解成任务是放在队列里面的,要被调度到线程中去执行)特点:队列先进先出,排在前面的任务最先执行。
分类:队列分为串行、并行、主队列、全局队列。
任务的执行是在线程上去执行的。分为同步和异步。
所以就可以分成:串行队列同步执行、串行队列异步执行、并行队列同步执行、并行队列异步执行。
GCD实现原理:
GCD有一个底层线程池,这个池中存放的是一个个的线程。之所以称为“池”,是因为这个“池”中的线程是可以重用的,当一段时间后没有任务在这个线程上执行的话,这个线程就会被销毁。注意:开多少条线程是由底层线程池决定的(线程建议控制再3~5条),池是系统自动来维护,不需要我们程序员来维护。
我们只关心的是向队列中添加任务,队列调度即可。
定义:调用方法(viewDidLoad)的队列(主队列)恰好是同步 *** 作(dispatch_sync)所针对的队列(dispatch_get_main_queue)。
示例1:
输出结果:
dispatch_sync 和 dispatch_async 区别:
dispatch_async(queue,block) async 异步队列,dispatch_async 函数会立即返回, block会在后台异步执行。
dispatch_sync(queue,block) sync 同步队列,dispatch_sync 函数不会立即返回,及阻塞当前线程,等待 block同步执行完成。
以上例子就会死锁,因为viewDidLoad的这个任务是被主队列调用的的,而dispatch_sync不会立即返回,而是先阻塞当前的主线程,直到这个block执行完毕,因为主线程被阻碍了,啥也干不了了(只有一个线程还被阻塞了,就会造成死锁),所以这个block就永远没有机会执行了,所以就会造成死锁。
示例2:
输出结果:
示例2就不会造成死锁,因为dispatch_async会立即返回,所以会先输出3,而异步会创建一个新的线程来执行block块,所以2最后输出。但是2和3的顺序不一定。
示例3:
输出结果:
示例3也不会造成死锁,因为dispatch_sync不会立即返回,而是先阻塞主线程,再将任务2加入到一个全局队列的一个线程上去执行,执行完之后返回到主队列,此时主线程不在阻塞,再继续执行任务3。
示例4:
输出结果:
因为dispatch_async不会等待,所以顺序是1-4-2-3-5或1-2-4-3-5,其中任务1和4是在主线程执行的,而2是在全局队列上被调用的,执行完2之后,会阻塞当前的线程(全局队列上的),紧接着会回到主队列上的主线程上执行任务3,任务3执行完之后,会继续执行5,此时全局队列上的线程也不堵塞了。
注意:线程同步阻塞后不一定能造成死锁,还要看看还有没有其他线程去执行那个block,如果能有,就能解锁阻塞的线程,继续执行任务。如果没有,那就是死锁了。
示例5:
输出结果:
最终结果还是会导致死锁,因为dispatch_queue_create创建队列的时候传入NULL默认是串行队列,所以执行任务2之后,会阻塞掉当前线程,直到任务3的block执行完成,又因为当前线程被阻塞掉了,block也无法执行,导致相互等待造成死锁
示例6:
输出结果:>=5
因为self.num++ *** 作是异步的,不一定能立马返回结果,所以在进入下次while循环的时候,self.num(主线程)可能还是0,所以循环肯定至少5次,最理想的情况下,5次全部都返回结果,而NSLog是会等待异步结果返回才会打印,所以输出结果>=5
示例7:
输出结果为:<1000
因为总共循环1000次,并不是每次结果都有返回,所以最终打印的self.num肯定小于1000
参考链接
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)