iOS开发 在异步线程里面添加定时器,或者perform afterDelay时不响应的问题

iOS开发 在异步线程里面添加定时器,或者perform afterDelay时不响应的问题,第1张

我们创建一个异步线程,然后在异步线程中添加了一个定时器或者 self.perform( with: afterDelay: ) 时,等时间到了,却发现没有响应对应的方法。

原因是:在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

参考链接


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/11550798.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-16
下一篇 2023-05-16

发表评论

登录后才能评论

评论列表(0条)

保存