主队列:
专门负责在主线程上调度任务,不会在子线程上调度任务,在主队列不允许开新线程。
主队列的特点:只在主线程运行,不开新线程。
异步执行:会开新线程,在新线程执行。
异步执行特点:不需要马上执行。
异步主队列:不会开辟新线程,只在主线程上顺序执行。
异步主队列的特点:主队列上的任务不会马上执行而是只把任务放到主队列,等线程有空时才去执行。
同步执行特点:不会开辟新线程,会马上执行。
2. 全局队列能供所有的应用程序共享。
3. 在MRC开发中,全局队列不需要释放,但是并发队列需要释放。
二者调度任务的方式相同。
注意:并发队列有名称,可以方便系统运行出错时根据队列名称在日志中进行查找。
GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建。使用dispatch_get_global_queue函数获取全局的并发队列。
dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority, unsigned long flags);
priority: 队列的优先级设为0即可 flags:此参数暂时无用,用0即可。举例如下:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 获得全局并发队列
全局并发队列的优先级:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
GCD中获取串行队列有2种路径
使用dispatch_queue_create函数创建串行队dispatch_queue_t
dispatch_queue_create(const char *label, // 队列名称
dispatch_queue_attr_t attr // 队列属性,如果是串行就传NULL
);具体使用如下:
dispatch_queue_t queue =dispatch_queue_create(“aaa”,NULL); // 创建串行队列
dispatch_release(queue); // 非ARC需要释放手动创建的队列。
使用主队列(跟主线程相关联的队列)
主队列是GCD自带的一种特殊的串行队列。
放到主队列中的任务,都会放到主线程中执行。
使用dispatch_get_main_queue()获得主队列
主队列的特点:只在主线程运行,不开新线程。
异步执行:会开新线程,在新线程执行。
异步执行特点:不需要马上执行。
异步主队列:不会开辟新线程,只在主线程上顺序执行。
异步主队列的特点:主队列上的任务不会马上执行而是只把任务放到主队列,等线程有空时才去执行。
同步执行特点:不会开辟新线程,会马上执行。
主队列同步执行特点:会因为主队列和所在方法的相互等待造成死锁,引起线程阻塞。
全局队列与并发队列的区别:
1. 全局队列没有名称,并发队列有名称。2. 全局队列能供所有的应用程序共享。
3. 在MRC开发中,全局队列不需要释放,但是并发队列需要释放。
二者调度任务的方式相同。
注意:并发队列有名称,可以方便系统运行出错时根据队列名称在日志中进行查找。
GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建。使用dispatch_get_global_queue函数获取全局的并发队列。
dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority, unsigned long flags);
priority: 队列的优先级设为0即可 flags:此参数暂时无用,用0即可。举例如下:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 获得全局并发队列
全局并发队列的优先级:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
GCD中获取串行队列有2种路径
使用dispatch_queue_create函数创建串行队dispatch_queue_t
dispatch_queue_create(const char *label, // 队列名称
dispatch_queue_attr_t attr // 队列属性,如果是串行就传NULL
);具体使用如下:
dispatch_queue_t queue =dispatch_queue_create(“aaa”,NULL); // 创建串行队列
dispatch_release(queue); // 非ARC需要释放手动创建的队列。
使用主队列(跟主线程相关联的队列)
主队列是GCD自带的一种特殊的串行队列。
放到主队列中的任务,都会放到主线程中执行。
使用dispatch_get_main_queue()获得主队列
dispatch_queue_t queue = dispatch_get_main_queue();
各种队列的执行效果如下图所示:
代码运行如下:
//
// ViewController.m
// GCD主队列
//
// Created by apple on 15/10/21.
// Copyright (c) 2015年 LiuXun. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
// 核心概念:
// 任务:Block 即将任务保存到一个Block中去。
// 队列: 把任务放到队列里面,队列先进先出的原则,把任务一个个取出(放到对应的线程)执行。
// 串行队列:顺序执行。即一个一个的执行。
// 并行队列:同时执行。同时执行很多个任务。
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self gcdTest3];
}
#pragma mark GCD 演练
/*
串行队列:顺序,一个一个执行。
同步:在当前线程执行,不会开辟新线程。
dispatch:调度,GCD里面的函数都是以dispatch开头的。
*/
-(void)gcdTest1
{
// 1. 创建一个串行队列
// 参数:1.队列标签(纯c语言) 2.队列的属性
dispatch_queue_t queue = dispatch_queue_create("itcast", DISPATCH_QUEUE_SERIAL);
// 2. 同步执行任务
// 一般只要使用“同步” 执行,串行队列对添加的任务,会立马执行。
dispatch_sync(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
NSLog(@"完成!");
}
/**
串行队列:任务必须要一个一个先后执行。
异步执行:肯定会开新线程,在新线程执行。
结果:只会开辟一个线程,而且所有任务都在这个新的线程里面执行。
*/
-(void)gcdTest2
{
// 1. 串行队列
dispatch_queue_t queue = dispatch_queue_create("itcast", DISPATCH_QUEUE_SERIAL);
// 按住command进入, #define DISPATCH_QUEUE_SERIAL NULL
// DISPATCH_QUEUE_SERIAL 等于直接写NULL, 且开发的时候都使用NULL
// 2. 异步执行
for (int i=0 ; i<10 ; i++) {
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
}
/**
并发队列:可以同时执行多个任务,
异步执行:肯定会开新线程,在新线程执行。
结果:会开很多个线程,同时执行。
*/
-(void)gcdTest3
{
// 1. 并发队列
dispatch_queue_t queue = dispatch_queue_create("cz", DISPATCH_QUEUE_CONCURRENT);
// 异步执行任务
for (int i=0 ; i<10 ; i++) {
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
}
/**
并发队列:可以同时执行多个任务
同步执行:不会开辟新线程,是在当前线程执行。
结果:不开新线程,顺序执行。
*/
-(void)gcdTest4
{
// 并发队列
dispatch_queue_t queue = dispatch_queue_create("itcast", DISPATCH_QUEUE_CONCURRENT);
for (int i=0 ; i< 10; i++) {
dispatch_sync(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
/**
解析如下:
串行队列:即要求按顺序挨个执行队列内的任务,即一次只执行一个。
并行队列:即要求同时执行队列内的任务。即一次要执行一个或多个队列内的任务。
同步执行:即只在当前线程执行队列内的任务,不会另外开辟新的线程。
异步执行:即开辟一个或多个新的线程来执行队列内的任务,让新的线程来执行。
串行队列同步执行:即由当前线程按顺序执行队列内的任务,不会开辟新的线程。
串行队列异步执行:即另外开辟一个新的线程(仅仅一个),并由这个新的线程来顺序执行队列内的任务,因为异步就是另外开辟线程,又因为串行队列一次只要求执行一个,所以只开辟一个新的线程来顺序执行即可。
并行队列同步执行:即由当前线程同时执行队列内的任务。由于当前单线程是无法实现同时执行多个任务即无法一次执行多个任务,所以只会由当前线程顺序执行队列内的任务。
并行队列异步执行:另外开辟多个线程来同时执行队列内的任务。因为队列内的任务要求同时执行多个,又可以开辟新的线程。所以会开辟多个新的线程来同时执行队列内的任务。但执行任务的顺序不确定,且开辟新线程的个数不确定。
需要注意的是:同步只在当前线程执行。异步只在别的线程执行。
*/
/*****************************************************************************************/
#pragma mark - 主队列
/**
主队列:专门负责在主线程上调度任务,不会在子线程调度任务,在主队列不允许开新线程。
主队列特点:不允许开新线程。
异步执行:会开新线程,在新线程执行。
异步特点:异步任务不需要马上执行,只是把任务放到主队列,等线程有空再去执行,也就是等gcdTest5执行完毕,主线程就有空了。
结果:不开线程,只能在主线程上,顺序执行。
*/
-(void) gcdTest5
{
// 1. 获得主队列—> 程序启动以后至少有一个主线程—> 一开始就会创建主队列。
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"开始------------------------");
// 2. 异步执行任务
for(int i=0; i<10; i++){
NSLog(@"调度前");
// 异步:把任务放到主队列里,但是不需要马上执行。
dispatch_async(queue, ^{ // 也就是说,把{}内的任务先放到队列里面,等主线程别的任务完成之后才执行。
NSLog(@"%@ %d", [NSThread currentThread], i);
});
NSLog(@"睡会");
[NSThread sleepForTimeInterval:1.0];
}
NSLog(@"完成------------------------");
/**
之所以将放到主队列内的任务最后执行,是因为当前队列所在的gcdTest5方法正由主线程进行执行,只有将先调度的gcdTest5执行完毕,才会执行加在队列内的任务。注意在执行方法过程中只是先把任务加到队列中。
*/
}
/**
主队列:专门负责在主线程上调度任务,不会在子线程调度任务,在主队列不允许开新线程。
同步执行:要马上执行。
结果:死锁。
*/
-(void)gcdTest6
{
// 1. 获得主队列—> 程序启动以后至少有一个主线程—> 一开始就会创建主队列。
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"开始------------------------");
// 2. 同步执行任务
for(int i=0; i<10; i++){
NSLog(@"调度前");
// 同步:把任务放到主队列里,但是需要马上执行。
dispatch_sync(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
NSLog(@"睡会");
[NSThread sleepForTimeInterval:1.0];
}
NSLog(@"完成------------------------");
/**
同步任务需要马上执行,但是主线程上面正在执行gcdTest6。所以需要等gcdTest6执行完毕,但是gcdTest6也在等主队列内的任务执行完毕。相互等待造成主线程阻塞。产生死锁。
*/
}
/******************************************************************************************/
#pragma mark GCD- 同步任务的所用
-(void)gcdTest7
{
// 并发队列
dispatch_queue_t queue = dispatch_queue_create("cz", DISPATCH_QUEUE_CONCURRENT);
/**
例子:有一个小说下载网站
- 必须登录,才能下载小说
有三个任务:
1. 下载任务
2. 下载小说A
3. 下载小说B
*/
// 添加任务
// 同步任务:需要马上执行,不会开辟新线程。
dispatch_sync(queue, ^{
NSLog(@"用户登录 %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"下载小说A%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"下载小说B %@", [NSThread currentThread]);
});
}
/***************************************************************************************/
#pragma mark- GCD全局队列
-(void)gcdTest8
{
// 获得全局队列
/** 一般不修改优先级
第一个参数,一般写0 (可以适配IOS7或IOS8)
第二个参数,保留参数,0
IOS7
DISPATCH_QUEUE_PRIORITY_HIGH 2 高优先级
DISPATCH_QUEUE_PRIORITY_DEFAULT 0 默认优先级
DISPATCH_QUEUE_PRIORITY_LOW (-2) 低优先级
DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN 后台优先级(最低)
IOS8 左边与IOS7对照
DISPATCH_QUEUE_PRIORITY_HIGH: QOS_CLASS_USER_INITIATED
DISPATCH_QUEUE_PRIORITY_DEFAULT: QOS_CLASS_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW: QOS_CLASS_UTILITY
DISPATCH_QUEUE_PRIORITY_BACKGROUND: QOS_CLASS_BACKGROUND
为了对IOS7或8都使用,所以写0即可
*/
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 异步执行任务
for (int i=0 ; i<10 ; i++) {
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
}
/**
全局队列与并发队列的区别:
1. 全局队列没有名称,并发队列有名称。
2. 全局队列,是供所有的应用程序共享。
3. 在MRC开发中,全局队列不需要释放,但并发队列需要释放。
对比:调度任务的方式相同。
*/
@end
运行结果如下:
主队列异步执行如下:
主队列同步执行如下:
gcd同步任务执行如下:
全局并发队列执行异步任务如下: