iOS开发笔记5:多线程之NSThread、NSOperation及GCD

时间:2022-11-16 18:27:06

    这篇主要总结下iOS开发中多线程的使用,多线程开发一般使用NSThread、NSOperation及GCD三种方式,常用GCD及NSOperation。

    1.NSThread

      创建线程主要有以下三种方式

     iOS开发笔记5:多线程之NSThread、NSOperation及GCD

     需要注意的是对于多个线程可能同时访问一个对象的时候,使用“@synchronized”来解决这类线程同步问题。

     在子线程中通知主线程通常使用以下两种办法:

     iOS开发笔记5:多线程之NSThread、NSOperation及GCD  

    2.NSOperation

     NSOperation有三种使用方式,分别是NSInvocationOperation、NSBlockOperation以及自定义NSOperation操作,并可对NSOperation设置依赖关系,进而确定任务执行的先后顺序,还可以对任务的状态进行监控甚至控制,以及设置线程最大并发数量等等。

    (1)NSInvocationOperation

      首先是NSInvocationOperation方式创建线程如图所示,需要注意的是这种方式创建的操作只有加入到队列去执行才是异步操作,否则还是在主线程同步执行

iOS开发笔记5:多线程之NSThread、NSOperation及GCDiOS开发笔记5:多线程之NSThread、NSOperation及GCD

       加入到队列自动执行时,会新建线程异步执行

iOS开发笔记5:多线程之NSThread、NSOperation及GCDiOS开发笔记5:多线程之NSThread、NSOperation及GCD

    (2)NSBlockOperation

      第二种则是使用NSBlockOperation,同样需要注意的是当操作的任务数只有一个时,任务会在当前线程同步执行

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

      当任务数大于1的时候,会开启新线程并异步执行

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

       当把NSBlockOperation定义的操作加入到队列中时,会以异步并发的方式去执行这些任务

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

     (3)继承NSOperation,自定义Operation

       这种方法较为灵活,通过继承NSOperation并重写相关方法实现,例如SDWebImage就用到了这种方式。

     (4)设置依赖

       如果任务之间有先后顺序依赖,可以对他们设置依赖关系解决这个问题,如图所示,operation1依赖operation2,而operation2又依赖于operation3,于是执行顺序为operation3、operation2、operation1

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

     (5)设置任务最大并发数

     可以通过设置maxConcurrentOperationCount限定任务并发数量,避免并发操作消耗太多资源

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

    (6)任务状态的监控以及设置

      可以获取到任务的执行状态,是否执行中还是取消了或者完成了等等

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

    需要注意的是,发送取消任务的消息,任务并不一定就真的取消,因为加入到队列以后,任务的执行都是由系统来管理了,取消成功的前提是任务还没有开始执行,即使该任务成功取消了,也还是会被系统认定为任务已经完成finished,所以如果有其他任务依赖于已经被取消的任务,需要用“isCancelled”进行判断,尤其是任务完成回调事件里做一些操作的话,可能说的有点绕,详细见下图:

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

      如果不进行判断,即使operation3已经取消了,由于系统认为取消的任务也算finished,所以operation3的任务完成回调事件仍然触发

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

     更详细的可以参考Concurrency Programming Guide中这部分的内容

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

     当然,还可以直接对整个列进行管理,包括挂起或恢复队列中所有任务,取消队列里所有任务等等

    iOS开发笔记5:多线程之NSThread、NSOperation及GCD

    3.GCD

    GCD的使用主要有以下几种方式:

   (1)在主线程中添加任务,dispatch_async异步方式执行,常见使用场景是进入以后,异步加载相关图片信息

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

    (2)GCD中解决线程同步的问题可以使用串行队列,串行队列里任务会按照添加顺序依次执行,需要注意的是以distpatch_sync同步方式执行任务,所有任务都是在主线程进行的

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

    (3)在串行队列中以dispatch_async异步方式执行任务,则系统开启一个新线程执行任务

iOS开发笔记5:多线程之NSThread、NSOperation及GCD   

     (4)在并发队列中,以dispatch_async异步方式执行任务,则系统会根据任务数量建立一定数量的线程来执行任务,注意这里用的是全局并发队列。

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

     (5)GCD方式执行延时任务

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

     上图为回到主线程执行延时任务,下图为开启新的线程执行延时任务

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

     (6)队列组

      当需要同时执行多个任务,例如同时下载多张图片,并对图片进行处理显示这样类似的应用场景时,可以通过队列组的方式并发执行任务,提高效率,使用方式如图

iOS开发笔记5:多线程之NSThread、NSOperation及GCD

     (7)解决线程同步的问题除了使用串行队列外,还可以使用信号量来解决,详细参考Concurrency Programming Guide,另外需要注意的是以下两个使用方式会产生问题

      一个是在主线程以dispatch_sync同步方式执行任务会死锁

    iOS开发笔记5:多线程之NSThread、NSOperation及GCD

    另一个是在并行队列中以dispatch_sync同步方式执行任务,会失去并发的意义,最终所有任务都还是在主线程中一个一个执行

    iOS开发笔记5:多线程之NSThread、NSOperation及GCD

    4.总结

     一般情况用NSOperation和GCD可以满足应用需求,GCD方式使用起来已经足够简洁,而NSOperation使用起来则更加灵活方便,可以监听任务执行状态,取消任务,设置任务最大并发数量等等。