原因是:在iOS中,不管是用Timer也好,还是使用 perfor afterDelay 方法也好,其本质都是会创建一个定时器。而定时器的工作原理,就是添加到runloop中,靠事件驱动来循环触发的。所以,这个触发条件的核心就是runloop必须要在运行。其实在每一条线程里面,都包含了一个runloop。但是呢,只有在主线程里面的runloop是默认开启的,其他子线程的runloop是要我们去手动开启的。这也就是为什么我们直接在主线程中添加一个定时器,就可以直接运行,而在异步线程中,却出现无法响应的问题。
{
dispatch_async(dispatch_queue_create(0, 0), ^{ // 异步子线程任务,异步释放资源,网络请求 }
dispatch_async(dispatch_get_main_queue(), ^{
//资源调度放到主线程
})
}
概念:队列只负责任务的调度,而不负责任务的执行,任务是在线程中执行的。(可以理解成任务是放在队列里面的,要被调度到线程中去执行)特点:队列先进先出,排在前面的任务最先执行。
分类:队列分为串行、并行、主队列、全局队列。
任务的执行是在线程上去执行的。分为同步和异步。
所以就可以分成:串行队列同步执行、串行队列异步执行、并行队列同步执行、并行队列异步执行。
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条)