您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线程 gcd