iOS多线程

iOS多线程基础

在iOS中,多线程的概念应该算是比好理解的了.并没有想象中那么难搞.简单的概念像线程/进程这些概念就不说了.

多线程其实真对单核的CPU来设计的.CPU同一时间只能执行一条线程.而多线程就是让CPU快速的在多个线程之间进行调度

多线程优点:

能够适当的提高程序的执行效率

能够适当提高资源利用率

缺点:

开启线程需要一定的内存空间,默认的一条线程占用栈区内存512KB

线程过多会导致CPU在线程上调度上的开销比较大

程序设计比较复杂,比如线程间的通信/多线程的数据共享

iOS应用程序中都是一个主线程,也成为UI线程

那么主线程的作用就是用来更新UI,显示/刷新UI界面

处理UI时间: 比如点击/滚动/拖拽/手势

注意:不能将耗时操作放在主线程,这样会给用户一种卡的"体验"


说下串行,并行,其实很简单就像你用浏览器下载和用迅雷下载,浏览器下载一般都是一个接一个的去下载.而迅雷就会同时去下载你所需要的所有东西.

简单入门级的多线程演示:

touchBegin{

[self  performselector:@selector(nsoperation)  withObject:nil ]

}

- (void) nsoperation {

for (int i = 0 , i < 50000 , i++){

nslog(" %d  %d",i, [NSTread currentThread]);

   }

}

iOS多线程技术--pthread

pthread是一套C语言的多线程API 使用难度比较大 需要程序员手动管理线程的生命周期  能够跨平台/可移植  能够在UNIX/LINX/Windows 下运行  

但是使用起来比较困难,参数比较难懂 可参照 http://www.baidu.baike.com

iOS多线程--NSThread

是一套OC框架  使用更加面向对象,简单易用,可直接操作线程对象   偶尔使用

需要程序员手动管理线程的声明周期  

一般用来查看当前线程是否是主线程:

=1 当前线程是主线程,!=1 当前线程是在子线程

iOS多线程--GCD

旨在代替NSThread多线程技术,充分利用设备的多核

也是一套基于C语言的API  不需要程序员手动管理线程的声明周期   经常使用

iOS多线程--NSOperation

是一套OC的API,是对GCD的封装 使用更加面向对象   不需要程序员手动管理线程的声明周期

比GCD多一些更加简单实用的功能  也是经常使用  特别是在iOS4以后


iOS多线程中的锁

互斥锁:

@synchronized  是为了保证其中代码只有一天线程来执行

所以@synchronized的范围是越小效率才高

@synchronized()其中的参数  就是能够加锁的任意ocject对象

局部变量,是每一条线程单独拥有的,所以无法加锁   锁一定要是所有线程共享的对象

一般使用self   (全局的也是可以的)

自旋锁:

自旋锁存在于原子属性的内部

自旋锁的特点就是当发现有其他线程正在执行锁定的代码,该线程会用死循环的方式去等待锁定代码执行完毕

atomic(原子属性): 默认是线程安全的    当多个线程写入属性时,保证同一时间只有一条线程能够执行写入操作


线程间的通讯

在NSThread中线程间的通讯

方法: performSelectorOnMainThread: with object: waitUnitDone:

三个参数: 方法选择器,将该方法放到主线程执行

              传递给方法的参数

               是否等待被调用方法执行完成, 有可能也会等待调用方法执行完成! 几率极小!


NSThread的三种线程创建方法:

1. NSThread * thread = [[NSThread alloc]initWithTarget: selector: object:]   创建初始化一条线程

 启动线程    [thread start]

2. [NSThread detachNewThreadSelector: toTarget: withObject:]  会立即执行selector方法

就是会分离一个子线程取执行selector方法

3.[self performSelectorInbackground: withObject: ]

这是NSObject的一个分类方法,所有NSObject都可以使用此方法在其他线程执行方法,一旦指定,就会立即在后台线程执行方法   使用比较灵活

介绍下NSThread中的几个重要属性:

name: 一般在比较复杂的商业应用中会设置线程的名字,因为可以快速找出崩溃线程

isMainThread: 这个是用来检测是否是主线程的属性

threadPriority: 这个属性是用来设置线程的优先级(线程的优先级是 用一个浮点数来表示: 0~1.0 , 默认线程的优先级是0.5) 注意: 设置线程的优先级高,只是CPU会优先调用该线程,调用该线程的可能性会高,并不是会将该线程执行完后再去执行别的线程 .

线程的状态属性:

isExecuting: 只读属性,线程是否正在运行

isFinished: 只读属性,线城是否完成

isCancelled: 只读属性,线程是否被取消


GCD--Grand Central Dispatch

是苹果公司为 多核并行运算提出的 解决方案

GCD是轻量级的多线程技术

系统会自动管理线程的生命周期

GCD中2个核心概念:

任务: 同步/异步

队列: 串行/并发

程序员只需做两件事: 1. 定制任务,确定需要做的事情

                              2. 将任务添加到队列中( GCD会自动将任务从队列中取出,放到对应的线程, 任务的取出是遵循FIFO原则的:先进先出,后进后出)

调度任务,执行任务的方法: 同步/异步

同步: 一个任务没有执行完,就不会执行下一个任务

异步: 不用等待当前执行任务完成,就可以执行下一个任务

任务队列组合:

1.串行队列,同步任务

不会开启线程,顺序执行任务

2.串行队列,异步任务

会开启一条线程,顺序执行任务

3.并发队列,异步任务

会开启多条线程,每条线程都会执行任务,所以不会顺序

4.并发队列,同步任务

不会开线程,,顺序执行

小结: - 开不开线程,取决于任务是同步还是异步,同步不开,异步开

       - 开几条线程,取决于队列,串行开一条,并发开多条(异步任务)

主队列特点: 主队列不是主线程

主线程上有任务,主队列不会调度队列中的任务

主队列异步任务 : 等待主线程上的任务执行完毕会执行主队列中的任务

主队列同步任务 : 等待主线程上的任务执行完毕,同步任务:当前任务不执行完毕,不会执行下一条任务

所以会造成互相等待,死锁!!!

同步任务的特点:

- 可以在队列调度多个异步任务之前,指定一个同步任务,让所有异步任务等待同步任务执行完毕,这就是依赖关系

全局队列:(其实就是并发队列<感觉是根据任务的同步/异步来确定的>)

就是给程序员使用的,方便程序员使用的

全局队列和并发队列的区别:

1>名称(队列后边的参数<是个字符串其实就是队列的名称>),并发队列有名称,适合商业级软件跟踪错误报告

2>release , 在MRC开发时,并发队列需要使用 dispatch_release(q);

目前绝大多数的软件都会使用全局队列. 比如比较优秀的第三方框架会使用自定义的并发队列!

全局队列和串行队列的选择

全局队列:   并发,能够调度多个线程,执行效率高

               - 比较费电

串行队列:   一个接一个,只能够开启一条线程,执行效率比较低

               - 省电,省钱,省流量

所以选择是根据用户连网状态来选择:

- WIFI,可以多开线程, 6条

- 3G/4G,尽量少开线程,2~3条

延时操作:

dispatch_after(dispatch_time,(int64_t)(delayInSeconds * NSEC_PER_SEC)),

           dispatch_get_main_queue(),^{

});

一次性操作:   苹果提供了一个一次性执行的机制,不仅能够保证只被执行一次,而且是"线程安全"的

dispatch_once()

使用互斥锁也可以,但是效率低


调度组:

dispatch_group_t

可以将多个任务放在同一个调度组中,同时监听这多个任务的下载,最后用dispatch_group_notify来通知

其实就是用一个调度组,可以监听全局队列调度的任务,执行完毕后,在主队列执行最终处理

dispatch_group_notify本身是异步的,这个还可以用另一种方法还实现是:dispatch_group_wait()其中第二个参数就是等待时间,一般写DISPATCH_TIME_FOREVER

第二种使用方法,经常出现在三方框架中:AFN

dispatch_group_enter()      进入群组

dispatch_group_leave()       退出群组

这两个方法必须成对出现



NSOperation

核心概念就是 将"操作"添加到"队列"

NSOperation是一个抽象类,不能直接使用!

它是对GCD的面向对象的的封装

目的:定义子类共有的属性和方法

子类: - NSInvocationOperation

       - NSBlockOperation

NSInvocationOperation:

只需要创建队列,执行start方法,就可以使用.

本质上就是GCD中的并发队列, 异步任务的执行


NSBlockOperation:

可以直接来一个全局的队列属性,懒加载之后,可以对所有的NSOperation的子类,添加到队列!

回主线程,直接[NSOperationQueue mainQueue]addOperationWithBlock:^ 就可以回主线程更新UI了非常简单好用

最大并发操作数:

从iOS8开始,无论是GCD还是NSOperation,都会开启很多线程,在iOS7以前GCD通常只会开启5~6条线程

线程数的增加说明了:

1 >底层的线程池变大了,能够拿到的线程资源更多了!

2 >对控制同时并发的线程数,要求更高了.

暂停/继续/取消全部操作:

暂停/继续:  NSOperation中的属性isSuspended 是否挂起

可以对isSuspended判断,判断队列是否挂起,来做任务的暂停或者继续.

1.在设置队列的挂起属性(isSuspended)时,并不会判断队列中是否有操作

所以如果不希望用户有困惑,可以提前做判断,就是对队列的operationCount属性进行判断

2.在暂停的时候,队列中的操作数是包括正在执行的操作,再次继续的时候,如果之前正在执行的操作已经完成,那么队列中的操作数就只有没有调度的操作

取消所有的操作:

通过设置队列的cancelAllOperations属性,可以取消队列的所有操作

注意: 这个取消属性,也是不会取消正在执行的操作

依赖关系:

NSOperation提供了依赖关系

NSOperation的所有操作都是异步的,但是为了建立操作之间的依赖关系,所以提供了dependency的功能

GCD中可以通过同步任务来实现,也可以通过串行队列来实现

先设置以来关系: op2 addDenpendency: op1   即  任务2依赖任务1,任务2会等任务1完成

将所有操作都加入到队列中 addOperations:@[op1,op2,op3]  waitUntilFinished:

withUntilFinished这个参数类似于GCD中的dispatch_group_wait(g , DISPATCH_TIME_FOREVER)  是否等待所有操作完成

但是注意:  不要指定循环依赖,虽然不会死锁,但是队列会不工作!!!以前的Xcode版本会死锁.

指定依赖关系是可以跨队列进行的.  将op1,op2添加到队列上,将op3添加到主队列上,一样按照指定的依赖关系执行.


NSOperation & GCD的对比

GCD  iOS4.0之后推出的针对多核处理器并做了优化的并发技术,是C语言的

- 将"任务"添加到"队列(串行/并发/全局/主队列)",并且指定执行任务的函数(同步/异步)

- 线程间的通讯  dispatch_get_main_queue()

- 提供了一些NSOperation不具备的功能

       - 一次性执行

       - 延迟操作

       - 在NSOperation中也可实现,相对来说比较麻烦

NSOperation是在iOS2.0之后推出的,苹果推出GCD之后,对NSOperation底层重写了一遍

- 将"操作"(异步执行的任务)添加到队列(并发队列),就会立即异步执行

- 线程间的通讯  mainQueue

- 提供了一些GCD实现比较困难的功能

         - 最大线程并发数

         - 队列的暂停/继续

         - 取消所有操作

         - 指定操作之间的依赖关系 (GCD可以用同步任务来实现)

你可能感兴趣的:(iOS多线程)