多线程编程
文章目录
IOS开发中多线程
- 主线程
- 一个iOS程序运行后,默认会开启1条线程,称为“主线程”或“UI线程”
- 作用
- 显示和刷新界面
- 处理UI事件(点击、滚动、拖拽等)
- 注意事项
- 耗时操作不能放在主线程中没,比如资源记载,文件下载,等比较耗时间的任务,不然会卡死界面
- 可以将耗时操作放到子线程中,将操作结果返回给主线程
IOS中得几种多线程实现方案
pThread
- 一套通用的多线程API
- 适用于Unix\Linux\Windows等系统
- 跨平台\可移植
- 使用难度大
- C语言,手动管理线程生命周期
NSThread
- 使用更加面向对象
简单易用,可直接操作线程对象 - OC,手动管理线程生命周期
- 使用更加面向对象
- GCD
- 旨在替代NSThread等线程技术,充分利用设备的多核
- C,自动管理
- NSOperation
- 基于GCD(底层是GCD)
- 比GCD多了一些更简单实用的功能
- 使用更加面向对象
- OC,自动管理
- 其中GCD和NSOperation比较常用
pThread 的使用
// 多线程 pThread |
NSThread 使用
- 这种方式创建的线程,在执行完线程函数里的方法后就由系统销毁了
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ |
创建子线程的其他方法
- performSelectorInBackground
- performSelector
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ |
线程的睡眠(阻塞)和退出
- (void)thread1:(NSString *)str |
线程同步 - 互斥锁
- 开启三个线程对同一个数据进行读写,就会出现问题,必须对读写数据进行处理,例如加锁
- 指令@synchronized()通过对一段代码的使用进行加锁。其他试图执行该段代码的线程都会被阻塞,直到加锁线程退出执行该段被保护的代码段,也就是说@synchronized()代码块中的最后一条语句已经被执行完毕的时候。
- @synchronized() 参数传入一个OC对象即可,self也可以
// 方法中对资源数的访问要加锁 |
GCD
- GCD - Grand Central Dispatch
- GCD中任务和队列
- 任务:执行什么操作
- 队列:存放任务
使用方式
- 定制自己的任务,添加到队列即可。线程会有GCD自动创建和销毁。
并发队列+异步任务:创建多个线程,并发执行
/* |
- 并发队列+同步任务:不会开启新线程,在主线程中同步执行各个子线程,也就是逐一执行,并且是添加过任务后立即执行,之后才能添加下一个任务
/* |
- 串行队列+同步任务:不会开启新线程,在父线程中同步执行各个子线程,也就是逐一执行,并且是添加过任务后立即执行,之后才能添加下一个任务
/* |
- 串行队列+异步任务:创建新线程,但是只会创建一个新线程,所有的任务都是在这个子线程里执行,执行顺序按照添加任务 的先后顺序,并且不是立即执行,而是等整个方法
/* |
- 主队列 是GCD自带的一种特殊的串行队列
- dispatch_get_main_queue()
- 全局并发队列
- dispatch_get_global_queue(优先级,0)
全局并发队列的特性和手动创建的队列一样
- dispatch_get_global_queue(优先级,0)
- 主队列+异步任务:不会创建新线程,所有的任务都是在这个父线程里执行,执行顺序按照添加任务 的先后顺序,并且不是立即执行,而是等整个方法结束后依次执行
/* |
- 主队列+同步任务:这个会产生问题,死锁,添加任务到主队列的任务要求立即执行,但是主队列是串行队列,当前任务要求执行完当前任务在执行新添加的任务。结果就是:两个任务互相等待,产生死锁
/* |
截止执行
- dispatch_barrier_async :截断线程执行,以上两个任务完成后才会执行这个任务,并在完成barrier后继续执行下面的任务
- 任务1,2的执行始终在任务3,4之前
- 只有在并发队列中才有阶段功能
延时执行
- (void)delay |
一次性代码
- 一次性代码内部默认就是线程安全的,不会出现多个线程同时访问内部代码
- (void)excuteOnce |
快速迭代
// 快速迭代,顺序不确定 |
队列组
/* |
NSOperation
- NSOperation是一抽象类,只能使用它的子类NSBlockOperation和NSInvocationOperation,或者自定义NSOperation。
1、NSInvocationOperation
- 使用方法initWithTarget:进行初始化。
- 默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作。
- 只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作。
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil]; |
2、NSBlockOperation
- 使用blockOperationWithBlock添加任务,或者addExecutionBlock添加多个任务。
- 只要添加的任务数量大于1就会自动创建多个线程,异步执行。
NSBlockOperation *ope1 = [NSBlockOperation blockOperationWithBlock:^{ |
3、NSOperationQueue
- NSOperation可以调用start方法来执行任务,但默认是同步执行的。
- 如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作。
// 添加到队列的任务会自动并发执行 |
4、最大并发数
- 设置队列的最大并发数
- maxConcurrentOperationCount = 2;,同一时刻只会有两条线程在执行
- [queue setMaxConcurrentOperationCount:2]; // 这样设置
- 如果设置为1,就变成串行队列了
// 最大并发数,同一时刻只会有两条线程在执行 |
5、任务依赖 addDependency
- 多个线程之间可以建立依赖关系
// 添加依赖:任务1和2的执行在3之前 |
6、线程通信
- 获取主队列mainQueue,将任务添加到主队列
- 如果定义的时全局的队列,可以在其他地方向这个队列添加任务。
// 获取主队列 |