一、调度组
- 有时候需要在多个异步任务都执行完成之后继续做某些事情,比如下载歌曲,等所有的歌曲都下载完毕之后 转到 主线程提示用户
//1 全局队列dispatch_queue_t queue = dispatch_get_global_queue(0, 0);//2 调度组dispatch_group_t group = dispatch_group_create();//3 添加任务//把任务添加到队列,等任务执行完成之后通知调度组dispatch_group_async(group, queue, ^{NSLog(@"歌曲1 %@",[NSThread currentThread]);});dispatch_group_async(group, queue, ^{NSLog(@"歌曲2 %@",[NSThread currentThread]);});dispatch_group_async(group, queue, ^{NSLog(@"歌曲3 %@",[NSThread currentThread]);});//4 所有任务都执行完成后,获得通知 (异步执行)//等调度组中队列的任务完成后,把block添加到指定的队列
// dispatch_group_notify(group, queue, ^{
// NSLog(@"okkkkkkk %@",[NSThread currentThread]);
// });dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//更新UI控件,提示用户NSLog(@"okkkkkkk %@",[NSThread currentThread]);});NSLog(@"over");
调度组原理
在终端中 输入man dispatch_group_async
//1 全局队列dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //2 调度组dispatch_group_t group = dispatch_group_create(); //ARC中不用写
// dispatch_retain(group);//3 进入调度组,执行此函数后,再添加的异步执行的block都会被group监听dispatch_group_enter(group); //4 添加任务dispatch_async(queue, ^{NSLog(@"!!--!!");dispatch_group_leave(group);//ARC中此行不用写,也不能写
// dispatch_release(group);});dispatch_group_enter(group);dispatch_async(queue, ^{NSLog(@"!!------!!");dispatch_group_leave(group);//ARC中此行不用写,也不能写//dispatch_release(group);});//5 获得调度组的通知dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(@"okkkkkkk %@",[NSThread currentThread]);});
//6 等待调度组 监听的队列中的所有任务全部执行完毕,才会执行后续代码,会阻塞线程(很少使用)
//下载三首歌曲,当歌曲都下载完毕 通知用户
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {[self demo2];
}
//调度组内部的原理
- (void)demo2 {//创建组dispatch_group_t group = dispatch_group_create();//创建队列dispatch_queue_t queue = dispatch_queue_create("hm", DISPATCH_QUEUE_CONCURRENT); //任务1dispatch_group_enter(group);dispatch_async(queue, ^{ NSLog(@"任务1");dispatch_group_leave(group);}); //任务2dispatch_group_enter(group);dispatch_async(queue, ^{ NSLog(@"任务2");dispatch_group_leave(group);});//任务3dispatch_group_enter(group);dispatch_async(queue, ^{[NSThread sleepForTimeInterval:2.0];NSLog(@"任务3");dispatch_group_leave(group);}); //等待组中的任务都执行完毕,才会执行dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(@"over");});//等待组中的任务都执行完毕,才会继续执行后续的代码dispatch_group_wait(group, DISPATCH_TIME_FOREVER);NSLog(@"hello ");
}
//演示调度组的基本使用
- (void)demo1 {//创建组dispatch_group_t group = dispatch_group_create();//队列dispatch_queue_t queue = dispatch_get_global_queue(0, 0);//下载第一首歌曲dispatch_group_async(group, queue, ^{NSLog(@"正在下载第一个歌曲");}); //下载第二首歌曲dispatch_group_async(group, queue, ^{NSLog(@"正在下载第二个歌曲");[NSThread sleepForTimeInterval:2.0]; });//下载第三首歌曲dispatch_group_async(group, queue, ^{NSLog(@"正在下载第三个歌曲");}); //当三个异步任务都执行完成,才执行dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(@"over %@",[NSThread currentThread]);});
}
二、NSOperation
- NSOperation的作用
- 是OC语言中基于GCD的面向对象的封装
- 使用起来比GCD更加简单(面向对象)
- 提供了一些用GCD不好实现的功能
- 苹果推荐使用,使用NSOperation不用关心线程以及线程的生命周期
- 查看NSOperation的头文件
- NSOperation是一个抽象类
- 不能直接使用(方法没有实现)
- 约束子类都具有共同的属性和方法
- NSOperation的子类
- NSInvocationOperation
- NSBlockOperation
- 自定义operation
- NSOperation是一个抽象类
- NSOperationQueue队列
使用步骤
- NSOperation和NSOperationQueue实现多线程的具体步骤
- 先将需要执行的操作封装到一个NSOperation对象中
- 然后将NSOperation对象添加到NSOperationQueue中
-
-
- 系统会自动将NSOperationQueue中的NSOperation取出来
- 将取出的NSOperation封装的操作放到一条新线程中执行
-
- 建NSInvocationOperation对象
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
- 调用start方法开始执行操作
- (void)start;
一旦执行操作,就会调用target的sel方法
注意
- 默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
- 只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作。
- 创建NSBlockOperation对象
+ (id)blockOperationWithBlock:(void (^)(void))block;
- 通过addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block;
注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作
三、NSOperationQueue
- NSOperationQueue的作用
NSOperation可以调用start方法来执行任务,但默认是同步执行的
如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
- 添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block;
@interface ViewController ()
//全局队列
@property (nonatomic, strong) NSOperationQueue *queue;
@end@implementation ViewController
//懒加载
- (NSOperationQueue *)queue {if (_queue == nil) {_queue = [[NSOperationQueue alloc] init];}return _queue;
}
//演示start
- (void)demo1 {//创建操作NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"hello %@",[NSThread currentThread]);}];//更新op的状态,执行main方法[op start]; //不会开新线程
}
//把操作添加到队列
- (void)demo2 {//创建队列NSOperationQueue *queue = [[NSOperationQueue alloc] init];//创建操作NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"hello %@",[NSThread currentThread]);}];//把操作添加到队列中[queue addOperation:op];
}
- (void)demo3 {NSOperationQueue *queue = [[NSOperationQueue alloc] init];[queue addOperationWithBlock:^{NSLog(@"hello %@",[NSThread currentThread]);}];
}
//全局队列
- (void)demo4 {
// //并发队列,异步执行
// for (int i = 0; i < 10; i++) {
// [self.queue addOperationWithBlock:^{
// NSLog(@"hello %d %@",i,[NSThread currentThread]);
// }];
// }
}
// 操作的 completionBlock
- (void)demo5 {NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{[NSThread sleepForTimeInterval:2];NSLog(@"hello %@",[NSThread currentThread]);}];//操作完成之后执行[op setCompletionBlock:^{NSLog(@"end %@",[NSThread currentThread]);}]; [self.queue addOperation:op];
}
四、线程间通信
- 主队列
- 添加到主队列的操作,最终都执行在主线程上
- [NSOperationQueue mainQueue]
- 当前队列
- 获取当前操作所在的队列
- [NSOperationQueue currentQueue]
- 模拟当图片下载完成后回归到主线程上更新UI
@interface ViewController ()
//全局队列
@property (nonatomic, strong) NSOperationQueue *queue;
@end@implementation ViewController
//懒加载
- (NSOperationQueue *)queue {if (_queue == nil) {_queue = [[NSOperationQueue alloc] init];}return _queue;
}
- (void)viewDidLoad {[super viewDidLoad]; [self.queue addOperationWithBlock:^{//异步下载图片NSLog(@"异步下载图片"); //获取当前队列
// [NSOperationQueue currentQueue] //线程间通信,回到主线程更新UI[[NSOperationQueue mainQueue] addOperationWithBlock:^{NSLog(@"更新UI");}];}];
}
1 消息循环主线程的消息循环默认开启,子线程的消息循环默认不开启
2 消息循环的目的保证程序不退出负责处理输入事件
3 输入事件和消息循环的模式输入事件的模式必须跟当前消息循环的模式匹配,输入事件才会执行
4 子线程消息循环 run
5 GCD队列 串行队列 并行队列 全局(并行)队列 主队列任务执行 同步执行 异步执行
6 各种组合6.1 串行队列同步执行 不开线程,顺序执行异步执行 开一个线程,顺序执行6.2 并行队列(全局队列)同步执行 不开线程,顺序执行异步执行 开多个线程,无序执行6.3 主队列同步执行 在主线程上执行的话会死锁异步执行 主线程,顺序执行
7 Barrier 阻塞 多线程中操作线程不安全的类,要小心
8 after 延迟执行
9 once 一次性执行 线程安全的单例 保证一个程序中只有一份单例对象(工具类)
10 调度组 让多个异步任务 都完成之后做一件事情
11 NSOperation 抽象类 抽象类中的方法都没有实现,等待子类去实现(约束子类)NSInvocationOperationNSBlockOperationstart 不开线程 会设置操作的状态 会调用main操作添加到队列 -- 并行队列,异步执行 开多个线程,无序执行
12 NSOperationQueue