06-GCD基本使用和组合
GCD
GCD的概念(自动管理)
- GCD有两个核心概念
- 任务 :执行什么操作
- 队列 :用来存放任务
- GCD的使用步骤
- 定制任务
- 确定想做的事
- 将任务添加到队列中
- GCD会自动将队列中的任务取出,放到对应的线程中执行
- FIFO 先进先出原则
- 定制任务
- 执行任务
- 同步
- dispath_sync(dispath_queue_t queue,^(void)block)
- 异步
- dispath_async(dispath_queue_t queue,^(void)block)
- 同步和异步的区别:
- 同步: 只能在
当前
线程中执行任务,不具备
开启新县城的能力 - 异步: 可以在
新的
线程中执行任务,具备
开启新线程的能力
- 同步: 只能在
- 同步
//dispath_queue_t 队列
//^(void)block 任务
dispath_async(dispath_queue_t queue,^(void)block)
同步/异步/并发/串行
-
同步:不能开启新线程
-
异步:可以开启新线程
-
并发:可以开启多个子线程
-
串行:只能在一个线程中执行(默认是串行队列)
-
注意
- 如果是同步函数,那么会等到函数中的任务执行完毕,才会执行后面的代码
- 如果是异步函数,那么不用等到函数中的任务执行完毕,就会执行后面的代码
--
系统提供的并发队列
// 系统内部已经给我们提供好了一个现成的并发队列
dispath_queue_t queue = dispath_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
//异步函数调用
dispath_async(queue,^(void)block)
系统提供的并发队列参数解析:
-
第一个参数: iOS8以前是优先级, iOS8以后是服务质量
-
iOS8以前
-
- DISPATCH_QUEUE_PRIORITY_HIGH 高优先级 2
-
- DISPATCH_QUEUE_PRIORITY_DEFAULT: 默认的优先级 0
-
- DISPATCH_QUEUE_PRIORITY_LOW: 低优先级 -2
-
- DISPATCH_QUEUE_PRIORITY_BACKGROUND:
-
-
iOS8以后
-
- QOS_CLASS_USER_INTERACTIVE 0x21 用户交互(用户迫切想执行任务)
-
- QOS_CLASS_USER_INITIATED 0x19 用户需要
-
- QOS_CLASS_DEFAULT 0x15 默认
-
- QOS_CLASS_UTILITY 0x11 工具(低优先级, 苹果推荐将耗时操作放到这种类型的队列中)
-
- QOS_CLASS_BACKGROUND 0x09 后台
-
- QOS_CLASS_UNSPECIFIED 0x00 没有设置
-
-
-
第二个参数: 废物(写0就是default,不管在ios8以前还是以后)
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
创建自定义队列,将任务加到队列中
- 任务多的话使用dispath_async会开启新线程
- 如果是并发,那么会开启多个线程(根据任务多少决定开启线程个数,一个线程可能处理多个任务)
串行队列+异步函数调用
- 会开启新的线程,但只会开启一个新的线程
- (void)syncSerial{
// 1.创建串行队列
dispatch_queue_t queue = dispatch_queue_create("com.520it.ln", DISPATCH_QUEUE_SERIAL);
//#define DISPATCH_QUEUE_SERIAL NULL
//串行等于NULL
/*
能够创建新线程的原因:
我们是使用"异步"函数调用
只创建1个子线程的原因:
我们的队列是串行队列
*/
// 2.将任务添加到队列中
dispatch_async(queue, ^{
NSLog(@"任务1 == %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务2 == %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务3 == %@", [NSThread currentThread]);
});
}
串行队列+同步函数调用
- 不会开启新的线程
- (void)syncSeral
{
// 1.创建串行队列
dispatch_queue_t queue = dispatch_queue_create("com.520it.ln", DISPATCH_QUEUE_SERIAL);
/*
能够创建新线程的原因:
我们是使用"异步"函数调用
只创建1个子线程的原因:
我们的队列是串行队列
*/
// 2.将任务添加到队列中
dispatch_sync(queue, ^{
NSLog(@"任务1 == %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务2 == %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务3 == %@", [NSThread currentThread]);
});
}
并发队列+同步函数调用
- (void)syncConCurrent
{
// 1.创建串行队列
dispatch_queue_t queue = dispatch_queue_create("com.520it.ln", DISPATCH_QUEUE_CONCURRENT);
/*
能够创建新线程的原因:
我们是使用"异步"函数调用
只创建1个子线程的原因:
我们的队列是串行队列
*/
// 2.将任务添加到队列中
dispatch_sync(queue, ^{
NSLog(@"任务1 == %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务2 == %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务3 == %@", [NSThread currentThread]);
});
}
并发队列+异步函数调用
- (void)asyncConCurrent
{
// 1.创建串行队列
dispatch_queue_t queue = dispatch_queue_create("com.520it.ln", DISPATCH_QUEUE_CONCURRENT);
/*
能够创建新线程的原因:
我们是使用"异步"函数调用
只创建1个子线程的原因:
我们的队列是串行队列
*/
// 2.将任务添加到队列中
dispatch_async(queue, ^{
NSLog(@"任务1 == %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务2 == %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务3 == %@", [NSThread currentThread]);
});
}
--
主队列
- 特点: 只要将任务添加到主队列中,那么任务
一定
会在主线程中执行,无论你是调用同步函数还是异步函数 - 主队列默认是串行
异步 + 主队列
:不会创建新的线程,并且任务是在主线程中执行- 如果是异步函数,那么不用等到函数中的任务执行完毕,就会执行后面的代码,不会产生死锁.
- (void)asyncMain{
dispath_queue_t queue = dispatch_get_main_queue();
//即便是异步函数,在主队列中也不会创建新的线程
dispath_async(queue,^{
NSLog(@"%@",[NSThread currentThread]);
});
}
注意避免死锁
- 导致死锁的原因(同步+主队列)
- sync函数在
主线程中执行
,并且会等待block执行完毕,先调用 - block是添加到主队列中的,也需要
主线程中执行
,后调用 注意:
如果是同步函数,那么会等到函数中的任务执行完毕,才会执行后面的代码
- sync函数在
- (void) viewDidLoad
{
//主队列默认是串行的
dispath_queue_t queue = dispatch_get_main_queue();
dispath_sync(queue,^{
NSLog(@"%@",[NSThread currentThread]);
});
}
- 解决办法
- block在子线程执行
- (void) viewDidLoad
{
//系统提供的并发队列
dispath_queue_t = queue = dispatch_get_global_queue(0,0);
dispath_async(queue,^{
//获取主线程
dispath_queue_t queue = dispatch_get_main_queue();
//小技巧:
//此时使用同步sync:NSLog(@"--------");一定会在dispatch执行完毕后执行
//若使用异步async:NSLog(@"--------");不一定会在dispatch执行完毕后执行
dispath_sync(queue,^{
NSLog(@"%@",[NSThread currentThread]);
});
NSLog(@"--------");
});
}