GCD的基本概念
-
1.GCD和NSThread的区别,GCD不需要程序员管理线程的生命周期,NSThread需要程序员手动管理生命周期
-
2.学习GCD之前需要先弄清一些概念
-
任务:执行什么样的操作
-
队列:用来存放任务
-
因为GCD不用程序员管理线程的声明周期,因此可以不管线程的创建和销毁
-
3.GCD的使用步骤
-
1.定制任务:确认想做的事情
-
2.将任务添加到队列中:GCD会自动将队列中的任务取出,放到对应的线程中执行
-
任务的取出遵循队列的FIFO原则:先进先出,后进后出。(这里需要和栈区分开来,栈是先进后出,因为,栈只有一个出口)
-
4.GCD中的任务
-
GCD中有两个用来执行任务的常用函数
-
同步
方式执行任务
- dispatch_sync(dispatch_queue_t _Nonnull queue, <^(void)block>)
-
异步
方式执行任务
- dispatch_async(dispatch_queue_t _Nonnull queue, <^(void)block>)
-
同步和异步的区别
-
同步:只能在当前线程中执行任务,不具备开线程的能力
-
异步:可以在新的线程中执行任务,具备开启新线程的能力
-
5.GCD队列的类型
-
并发队列(Concurrent Dispatch Queue)
-
可以让多个任务并发(同时)执行,自动开启多个线程同时执行任务
-
并发功能再有在异步 (dispatch_async)函数下才有效
-
串行队列(Serial Dispatch Queue)
-
让任务一个接着一个地执行,一个任务执行完毕后,再执行下一个任务
-
6.GCD任务和队列代码详述
@interface ViewController ()
@end
@implementation ViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self globlQueueAsyncCoucurrent];
}
//异步函数+串行队列:会开线程,开一条线程,队列中的任务是串行执行
-(void)asyncConcurrent
{
//1.创建队列
/**
const char *_Nullable label:C语言字符串,线程的标签
dispatch_queue_attr_t _Nullable attr:队列的类型
DISPATCH_QUEUE_CONCURRENT:并发
DISPATCH_QUEUE_SERIAL:串行
*/
dispatch_queue_t asyncQueue = dispatch_queue_create("lxc", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(asyncQueue, ^{
NSLog(@"queue1---%@",[NSThread currentThread]);
});
//2.封装任务->添加任务到队列中
/**
dispatch_queue_t queue:队列是哪个
dispatch_block_t block:block参数
*/
dispatch_async(asyncQueue, ^{
NSLog(@"queue2---%@",[NSThread currentThread]);
});
dispatch_async(asyncQueue, ^{
NSLog(@"queue3---%@",[NSThread currentThread]);
});
dispatch_async(asyncQueue, ^{
NSLog(@"queue4---%@",[NSThread currentThread]);
});
NSLog(@"----end----");
//线程没有顺序
}
//异步函数+串行队列:会一条开线程,队列中的任务是串行执行
-(void)asyncSerial
{
dispatch_queue_t asyncQueue = dispatch_queue_create("cyf", DISPATCH_QUEUE_SERIAL);
dispatch_async(asyncQueue, ^{
NSLog(@"queue1---%@",[NSThread currentThread]);
});
dispatch_async(asyncQueue, ^{
NSLog(@"queue2---%@",[NSThread currentThread]);
});
dispatch_async(asyncQueue, ^{
NSLog(@"queue3---%@",[NSThread currentThread]);
});
dispatch_async(asyncQueue, ^{
NSLog(@"queue4---%@",[NSThread currentThread]);
});
NSLog(@"----end----");
}
//同步函数+并行队列:不会开启线程,所有任务都在主线程中执行,队列中的任务是并行执行
-(void)syncConcurent
{
dispatch_queue_t syncQueue = dispatch_queue_create("23", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(syncQueue, ^{
NSLog(@"syncQueue1----%@",[NSThread currentThread]);
});
dispatch_sync(syncQueue, ^{
NSLog(@"syncQueue2----%@",[NSThread currentThread]);
});
dispatch_sync(syncQueue, ^{
NSLog(@"syncQueue3----%@",[NSThread currentThread]);
});
dispatch_sync(syncQueue, ^{
NSLog(@"syncQueue4----%@",[NSThread currentThread]);
});
}
//同步函数+串行队列:不会开启线程,所有的任务都在主线程中执行,队列中的任务是串行执行
-(void)syncSerial
{
dispatch_queue_t syncQueue = dispatch_queue_create("22", DISPATCH_QUEUE_SERIAL);
dispatch_sync(syncQueue, ^{
NSLog(@"syncQueue1----%@",[NSThread currentThread]);
});
dispatch_sync(syncQueue, ^{
NSLog(@"syncQueue2----%@",[NSThread currentThread]);
});
dispatch_sync(syncQueue, ^{
NSLog(@"syncQueue3----%@",[NSThread currentThread]);
});
dispatch_sync(syncQueue, ^{
NSLog(@"syncQueue4----%@",[NSThread currentThread]);
});
NSLog(@"---end---");
}
//全局并发队列+并发:不会创建线程,会从GCD本身就有全局并发队列,只是拿出,并且创建多少线程不受控制
-(void)globlQueueAsyncCoucurrent
{
/*
//获得全局并发队列:
第一个参数:队列的优先级
DISPATCH_QUEUE_PRIORITY_DEFAULT 默认 0
DISPATCH_QUEUE_PRIORITY_HIGH 最高 2
DISPATCH_QUEUE_PRIORITY_BACKGROUND 最低优先级 -1
DISPATCH_QUEUE_PRIORITY_LOW 低优先级 1
第二个参数:传0即可
*/
//获得全局并发队列,这个队列本身是存在的,在GCD中本身就有全局并发队列,只是拿过来用一下,需要注意的是全局并发队列,是不受控制的,并不是有多少任务就先多少线程
dispatch_queue_t globlQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globlQueue, ^{
NSLog(@"asyncQueue1----%@",[NSThread currentThread]);
});
dispatch_async(globlQueue, ^{
NSLog(@"asyncQueue2----%@",[NSThread currentThread]);
});
dispatch_async(globlQueue, ^{
NSLog(@"asyncQueue3----%@",[NSThread currentThread]);
});
dispatch_async(globlQueue, ^{
NSLog(@"asyncQueue4----%@",[NSThread currentThread]);
});
//全局并发队列没有顺序
}
@end
dispatch_queue_t queue = dispatch_get_global_queue(0,0);
/**
* @param DISPATCH_TIME_NOW 从现在开始计算时间
* @param int64_t 延迟的时间 2.0 GCD时间单位:纳秒
* @dispatch_get_main_queue 队列
CGD的定时任务可以控制几秒后再那个线程中执行
*/
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), queue, ^{
NSLog(@"-----GCD------%@",[NSThread currentThread]);
});
//一次性代码
//不能放在懒加载中的,应用场景:单例模式
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"---once----");
});
- ##### 栅栏函数
dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"download1-----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"download2-----%@",[NSThread currentThread]);
});
/**
* GCD栅栏函数
该函数可以控制多线程异步的执行顺序(哪个先执行哪个后执行)
注意:在使用栅栏函数的时候不可以使用全局并发队列
*/
dispatch_barrier_async(queue, ^{
NSLog(@"+++++++++++++++");
});
dispatch_async(queue, ^{
NSLog(@"download4-----%@",[NSThread currentThread]);
});
@param 10 迭代的次数
@param 队列(并发队列)
@param index 索引
@return
dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
NSLog(@"%zd-----%@",index,[NSThread currentThread]);
-
GCD队列组函数
- 队列组
- 如果有这么一种需求,首先分别异步执行2个耗时操作,其次等2个异步操作都执行完毕后,再回到主线程执行操作。如果遇到这种业务可以考虑用队列组实现
//1.创建队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//2.创建队列组
dispatch_group_t group = dispatch_group_create();
//3.队列组函数
/**
1.封装任务
2.把任务添加到队列中
3.会监听任务的执行情况,通知group
*/
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]);
});
//监听通知,当队列组中所有的任务都执行完毕的时候,进入到下面的方法
/**
* 监听通知的时候函数不会阻塞,内部本身是异步的
*/
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"end---%@",[NSThread currentThread]);
});
/**
监听通知的另一个函数,这个函数会一直等待,死等。直到队列组中所有的任务都执行完毕之后才能执行,内部本身是同步的
*/
dispatch_group_wait(group, DISPATCH_TIME_NOW);
NSLog(@"----end----");