在开发中涉及多线程一般会用GCD 因为强大且方便,以下是我对GCD的一些总结
任务
分为同步执行(sync)和异步执行(async)二种
同步执行
同步添加任务到指定的队列中,在添加的任务执行结束之前,会
一直等待
,直到队列里面的任务完成之后再继续执行。
只能在当前线程中执行任务,不具备开启新线程的能力
。
异步执行
异步添加任务到指定的队列中,它
不会做任何等待
,可以继续执行任务。
可以在新的线程中执行任务,具备开启新线程的能力
。
注意:异步执行(async)虽然具有开启新线程的能力,但是并不一定开启新线程。
队列(Dispatch Queue)
指用来存放任务的队列,是一种特殊的线性表,采用 FIFO(先进先出)的原则,分为二种队列:串行队列
和并发队列
。
串行队列(Serial
Dispatch Queue)
每次只有一个任务被执行。让任务一个接着一个地执行。(只开启一个线程,一个任务执行完毕后,再执行下一个任务)
并发队列(Concurrent
Dispatch Queue)
可以让多个任务并发(同时)执行。(可以开启多个线程,并且同时执行任务)
二者区别可以画个图解释
GCD 的使用步骤
1.创建一个队列(串行队列或并发队列)
2.将任务追加到任务的等待队列中,然后系统就会根据任务类型执行任务(同步执行或异步执行)
队列的创建方法
第一个参数
表示队列的唯一标识符,根据个人想法填,约束不大。第二个参数
用来识别是串行队列还是并发队
// 串行队列的创建方法
dispatch_queue_t queue = dispatch_queue_create("text", DISPATCH_QUEUE_SERIAL);
// 并发队列的创建方法
dispatch_queue_t queue = dispatch_queue_create("text", DISPATCH_QUEUE_CONCURRENT);
- 还有一些特殊的队列
主队列(Main Dispatch Queue)
:所有放在主队列中的任务,都会放到主线程中执行
// 主队列的获取
dispatch_queue_t queue = dispatch_get_main_queue();
全局并发队列(Global Dispatch Queue)
:就是一个系统提供的并发队列吧
第一个参数
表示队列优先级,一般用DISPATCH_QUEUE_PRIORITY_DEFAULT,第二个参数
不知道干嘛的,一般为0
// 全局并发队列的获取
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
任务的创建
// 同步执行任务创建方法
dispatch_sync(queue, ^{
// 这里放同步执行任务代码
});
// 异步执行任务创建方法
dispatch_async(queue, ^{
// 这里放异步执行任务代码
});
以上是GCD使用需要了解的............
然后会产生疑惑,任务和队列方式可以有6种
1.同步执行 + 并发队列
2.异步执行 + 并发队列
3.同步执行 + 串行队列
4.异步执行 + 串行队列
5.同步执行 + 主队列
6.异步执行 + 主队列
这里不做复杂演示,你可以直接查看表格结果
End
显然不是的
GCD线程间的切换
// 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 随便创建一个任务 模拟网络等耗时操作
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"1---%@",[NSThread currentThread]);
}
// 回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程进行UI操作
});
});
GCD 栅栏方法:dispatch_barrier_async
有这样一个需求,先执行某个异步操作,这个异步操作执行完成后再执行接下来的异步操作,这种情况就要用到栅栏
了·。
dispatch_queue_t queue = dispatch_queue_create("text", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
// 追加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(queue, ^{
// 追加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_barrier_async(queue, ^{
// 追加任务 barrier
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"barrier---%@",[NSThread currentThread]);// 打印当前线程
}
});
dispatch_async(queue, ^{
// 追加任务3
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(queue, ^{
// 追加任务4
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"4---%@",[NSThread currentThread]); // 打印当前线程
}
});
打印发现 3和4 都是在barrier执行完后执行的
GCD 延时执行方法:dispatch_after
:延迟几秒后执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 3.0秒后异步追加任务代码到主队列,并开始执行
NSLog(@"after---%@",[NSThread currentThread]); // 打印当前线程
});
GCD 一次性代码(只执行一次):dispatch_once
常在单例中看到
//一次性代码(只执行一次)dispatch_once
+ (PCCurrentUserMgr *)shareInstance {
static PCCurrentUserMgr *s_ins = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只执行1次的代码(这里面默认是线程安全的)
s_ins = [PCCurrentUserMgr new];
});
return s_ins;
}
未完待续