GCD&&单粒
2016-02-03 14:20
253 查看
GCD基本思想
GCD的基本思想是就将操作放在队列中去执行操作使用Blocks定义
队列负责调度任务执行所在的线程以及具体的执行时间
队列的特点是先进先出(FIFO)的,新添加至对列的操作都会排在队尾
GCD中的专用术语
同步函数和异步函数主要影响:能不能开启新的线程同步函数:只是在当前线程中执行任务,不具备开启新线程的能力
异步函数:可以在新的线程中执行任务,具备开启新线程的能力(特殊情况:在主队列中不会开启新线程)
并发队列和串行队列主要影响:任务的执行方式
并发队列:允许多个任务并发(同时)执行
穿行队列:一个任务执行完毕后,再执行下一个任务
同步函数 && 异步函数的小差别
- (void)syncConcurrent { // 1.获得全局的并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 2.将任务加入队列 dispatch_sync(queue, ^{ NSLog(@"1-----%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"2-----%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"3-----%@", [NSThread currentThread]); }); NSLog(@"syncConcurrent--------end");// 先打印上面的,在打印这一句 }
- (void)asyncConcurrent { // 1.获得全局的并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 2.将任务加入队列 dispatch_async(queue, ^{ for (NSInteger i = 0; i<10; i++) { NSLog(@"1-----%@", [NSThread currentThread]); } }); dispatch_async(queue, ^{ for (NSInteger i = 0; i<10; i++) { NSLog(@"2-----%@", [NSThread currentThread]); } }); dispatch_async(queue, ^{ for (NSInteger i = 0; i<10; i++) { NSLog(@"3-----%@", [NSThread currentThread]); } }); NSLog(@"asyncConcurrent--------end");// 先打印这一句,再打印上面的 // dispatch_release(queue); }
NSLog(@”syncConcurrent——–end”);
NSLog(@”asyncConcurrent——–end”);
明白上面两行都是什么时候调用
同步函数:任务加入队列后,立刻执行
异步函数:任务加入队列后,等会执行,可以理解为asyncConcurrent函数执行完,在执行任务
串行队列&&主队列
GCD中获得串行队列有两种途径使用
dispatch_queue_create函数创建串行队列
// 创建串行队列(队列类型传递NULL或者DISPATCH_QUEUE_SERIAL) dispatch_queue_t queue = dispatch_queue_create("AHUAN.queue", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue = dispatch_queue_create("AHUAN.queue", NULL);
dispatch_queue_t queue = dispatch_queue_create("AHUAN.queue", NULL); // 同步操作不会新建线程、操作顺序执行(一般不用) dispatch_sync(queue , ^{ NSLog(@"串行同步 %@", [NSThread currentThread]); }); // 异步操作会新建一个线程、操作顺序执行(非常有用!)场景:既不影响主线程,又需要顺序执行的操作! dispatch_async(queue , ^{ NSLog(@"串行异步 %@", [NSThread currentThread]); });
使用主队列(跟住线程相关联的队列)
主队列是GCD自带的一种特殊的串行队列
放在主队列中的任务,都会放到主线程中
使用
dispatch_get_main_queue()获得主队列
// 每一个应用程序对应唯一一个主队列,直接GET即可,在多线程开发中,使用主队列更新UI dispatch_queue_t queue = dispatch_get_main_queue(); // 主队列中的操作都应该在主线程上顺序执行的,不存在异步的概念 dispatch_async(queue, ^{ NSLog(@"主队列异步 %@", [NSThread currentThread]); }); // 主队列中添加的同步操作永远不会被执行,会死锁 dispatch_sync(queue, ^{ NSLog(@"主队列同步 %@", [NSThread currentThread]); });
并发队列&&全局队列
GCD中获得并发队列也有两种途径手动创建并发队列
dispatch_queue_t queue = dispatch_queue_create("cn.itcast.demoqueue", DISPATCH_QUEUE_CONCURRENT); // 同步操作不会新建线程,操作顺序执行 dispatch_sync(queue, ^{ NSLog(@"并行同步 %@", [NSThread currentThread]); }); // 异步操作会新建多个线程、操作无序执行(有用,容易出错!) // 队列前如果有其他任务,会等待前面的任务完成之后再执行 // 场景:既不影响主线程,又不需要顺序执行的操作! dispatch_async(queue, ^{ NSLog(@"并行异步 %@", [NSThread currentThread]); });
GCD默认已经提供了全局的并发队列,供整个应用使用,可以无需手动创建
// 全局队列是系统的,直接拿过来(GET)用就可以 // 与并行队列类似 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_queue_t queue = dispatch_get_global_queue(0, 0); // 优先级 0 就代表 DISPATCH_QUEUE_PRIORITY_DEFAULT
不同队列中嵌套dispatch_sync的结果
// 全局队列,都在主线程上执行,不会死锁 dispatch_queue_t q = dispa c97f tch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 并行队列,都在主线程上执行,不会死锁 dispatch_queue_t q = dispatch_queue_create("AHUNA.queue",DISPATCH_QUEUE_CONCURRENT); // 串行队列,会死锁,但是会执行嵌套同步操作之前的代码 dispatch_queue_t q = dispatch_queue_create("AHUNA.queue", DISPATCH_QUEUE_SERIAL); // 直接死锁 dispatch_queue_t q = dispatch_get_main_queue(); dispatch_sync(q, ^{ NSLog(@"同步任务 %@", [NSThread currentThread]); dispatch_sync(q, ^{ NSLog(@"同步任务 %@", [NSThread currentThread]); }); });
线程间的通信示例
从子线程回到主线程dispatch_async(dispatch_get_global_queue(0, 0), ^{ // 执行耗时的异步操作... dispatch_async(dispatch_get_main_queue(), ^{ // 回到主线程,执行UI刷新操作 }); });
GCD常用函数
执行任务的函数dispatch_barrier_async
执行任务的函数dispatch_barrier_async(<#dispatch_queue_t queue#>, ^{ <#code#> })
在这之前的任务结束后它才执行,而且它后面的任务等它执行完之后才会执行
这个queue不能是全局的并发队列,可以是我们自己创建的并发队列
一次性代码dispatch_once
确保某段代码在程序运行过程中只被执行1次static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // 这里面的代码整个程序只执行一次(这里面默认是线程安全的) });
延时执行
使用GCD函数dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2秒后执行这里的代码... });
调用NSObject的方法
[self performSelector:@selector(run) withObject:nil afterDelay:2.0]; // 2秒后在调用self的run方法
使用NSTimer
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO]; // 2秒后在调用self的run方法
快速迭代
使用dispatch_apply函数能进行快速迭代遍历// size_t iterations代表执行多少次 dispatch_apply(<#size_t iterations#>, <#dispatch_queue_t queue#>, ^(size_t index) { <#code#> // index顺序不确定 });
组队列
// 分别异步执行两个耗时的操作(下载图片),等2个异步操作都执行完毕后,再异步执行一个耗时操作(合成图片) // 然后在回到主线程中刷新UI界面 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 创建一个队列组 dispatch_group_t group = dispatch_group_create(); // 1.下载图片1 dispatch_group_async(group, queue, ^{ // 图片的网络路径 NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"]; // 加载图片 NSData *data = [NSData dataWithContentsOfURL:url]; // 生成图片 self.image1 = [UIImage imageWithData:data]; }); // 2.下载图片2 dispatch_group_async(group, queue, ^{ // 图片的网络路径 NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"]; // 加载图片 NSData *data = [NSData dataWithContentsOfURL:url]; // 生成图片 self.image2 = [UIImage imageWithData:data]; }); // 3.将图片1、图片2合成一张新的图片 dispatch_group_notify(group, queue, ^{ // 开启新的图形上下文 UIGraphicsBeginImageContext(CGSizeMake(100, 100)); // 绘制图片 [self.image1 drawInRect:CGRectMake(0, 0, 50, 100)]; [self.image2 drawInRect:CGRectMake(50, 0, 50, 100)]; // 取得上下文中的图片 UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); // 结束上下文 UIGraphicsEndImageContext(); // 回到主线程显示图片 dispatch_async(dispatch_get_main_queue(), ^{ // 4.将新图片显示出来 self.imageView.image = image; }); });
单粒模式
在.m中保留一个全局的static的实例:
static id_instance
// 重写allocWithZone:方法,在这里创建一个唯一的实例(注意线程安全) +(instancetype)allocWithZone:(struct _NSZone *)zone{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); return _instance; } // 提供1个类方法让外界访问唯一的实例 + (instancetype)sharedInstance{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; } // 实现copyWithZone:方法 - (id)copyWithZone:(struct _NSZone *)zone{ return _instance; }
相关文章推荐
- C#线程间不能调用剪切板的解决方法
- C#线程同步的三类情景分析
- C#获取进程或线程相关信息的方法
- C#停止线程的方法
- C#子线程更新UI控件的方法实例总结
- C#线程队列用法实例分析
- C++使用CriticalSection实现线程同步实例
- 基于C++实现的线程休眠代码
- VB读取线程、句柄及写入内存的API代码实例
- C#网络编程基础之进程和线程详解
- C#通过Semaphore类控制线程队列的方法
- C#多线程处理多个队列数据的方法
- C#实现线程安全的简易日志记录方法
- C#中线程同步对象的方法分析
- ASP.NET线程相关配置
- 浅析linux环境下一个进程最多能有多少个线程
- 再谈JavaScript线程
- C#实现终止正在执行的线程
- Java线程编程中的主线程讲解
- 解析Java线程同步锁的选择方法