首先要肯定:一个线程只能执行一个任务,执行完才会执行另外一个任务程序员
先总结一张图网络
同步和异步并发
dispatch_sync 是同步的方式执行任务
dispatch_async 是异步的方式执行任务
同步和异步的区别
同步:在当前线程中执行(不会开辟新线程,是在当前线程执行,通常使用同步执行任务会立马执行,‘写了跟没写同样’)
异步:在另外一条新的线程中执行(把任务放在主队列里,可是不须要立刻执行)异步
串行队列和并行队列async
串行队列:一个一个执行,就算在异步执行的时候,也只会开辟一条新线程(若是主线程是数字是1,那串行队列只会开辟出一个数字2的线程),而且全部的任务都会在新的线程中执行
dispatch_queue_t queue = dispatch_queue_create(“label”, DISPATCH_QUEUE_SERIAL);
或者
dispatch_queue_t queue = dispatch_queue_create(“label”, NULL); 这两种的建立方式是同样的 程序中会常常写成NULL;spa
并行队列:在异步执行时会开辟不少新的线程,能够同时执行多个任务,顺序是程序员没法控制的
dispatch_queue_t queue = dispatch_queue_create(“label”, DISPATCH_QUEUE_CONCURRENT);
并发队列的同步执行,不开辟新线程,一步一步执行任务
线程
GCD 主线程
1. 专门在主线程上调度任务
2. 不会开辟新线程,无论同步异步执行,只能在主线程上顺序执行code
主线程的异步执行任务blog
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self gcdText5]; } - (void)gcdText5 { // 1.得到主线程 dispatch_queue_t queue = dispatch_get_main_queue(); NSLog(@"1-------"); // 2.异步执行任务 // 把任务放在主队列里,可是不须要立刻执行 for (int i = 0; i < 10; i++) { NSLog(@"调度前-----"); // 任务:block dispatch_async(queue, ^{ NSLog(@"%@, %d", [NSThread currentThread], i); }); NSLog(@"睡会"); [NSThread sleepForTimeInterval:2.0]; } NSLog(@"完成"); }
这是运行顺序是以下图队列
2016-05-29 17:09:24.945 GCD[6702:82350] 1------- 2016-05-29 17:09:24.946 GCD[6702:82350] 调度前----- 2016-05-29 17:09:24.946 GCD[6702:82350] 睡会 2016-05-29 17:09:26.951 GCD[6702:82350] 调度前----- 2016-05-29 17:09:26.951 GCD[6702:82350] 睡会 2016-05-29 17:09:28.954 GCD[6702:82350] 调度前----- 2016-05-29 17:09:28.954 GCD[6702:82350] 睡会 2016-05-29 17:09:30.959 GCD[6702:82350] 调度前----- 2016-05-29 17:09:30.959 GCD[6702:82350] 睡会 2016-05-29 17:09:32.963 GCD[6702:82350] 调度前----- 2016-05-29 17:09:32.964 GCD[6702:82350] 睡会 2016-05-29 17:09:34.969 GCD[6702:82350] 调度前----- 2016-05-29 17:09:34.969 GCD[6702:82350] 睡会 2016-05-29 17:09:36.971 GCD[6702:82350] 调度前----- 2016-05-29 17:09:36.971 GCD[6702:82350] 睡会 2016-05-29 17:09:38.971 GCD[6702:82350] 调度前----- 2016-05-29 17:09:38.971 GCD[6702:82350] 睡会 2016-05-29 17:09:40.974 GCD[6702:82350] 调度前----- 2016-05-29 17:09:40.974 GCD[6702:82350] 睡会 2016-05-29 17:09:42.977 GCD[6702:82350] 调度前----- 2016-05-29 17:09:42.977 GCD[6702:82350] 睡会 2016-05-29 17:09:44.981 GCD[6702:82350] 完成 2016-05-29 17:09:44.981 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 0 2016-05-29 17:09:44.982 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 1 2016-05-29 17:09:44.982 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 2 2016-05-29 17:09:44.982 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 3 2016-05-29 17:09:44.982 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 4 2016-05-29 17:09:44.982 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 5 2016-05-29 17:09:44.983 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 6 2016-05-29 17:09:44.983 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 7 2016-05-29 17:09:44.983 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 8 2016-05-29 17:09:44.983 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 9
为何会产生这种效果呢
由于异步执行只是把任务放在队列中,不会立刻执行,由于主队列的特殊性又不能开辟新的线程,因此会等到主线程的任务执行完才会执行队列中的任务 , 如图
此时主线程正在执行gcdText5这个任务,
当gocText5任务执行完成后在执行 绿色的0,1任务
主线程的同步执行任务
只须要将代码
dispatch_async
换成
dispatch_sync
就能够了,这是运行效果回事这样的
这是由于
同步任务要立刻执行,可是线程没空,线程正在执行gcdText5,须要等gcdText5执行完,可是gcdText5在等这个同步任务执行结束,因此会形成主线程阻塞,产生死锁
全局队列
全局队列和并发队列的区别
1.全局队列没有名称,并发队列有名称
2.全局队列,是供全部的应用程序共享
3.在MRC开发中并发队列须要释放,全局队列不须要管理
// 全局队列:是苹果官方提供的,是指上也是并发队列 /* 参数:第一个参数,通常写 0 (能够适配iOS 7 & 8) (优先级)DISPATCH_QUEUE_PRIORITY_HIGH: QOS_CLASS_USER_INITIATED (0) DISPATCH_QUEUE_PRIORITY_DEFAULT: QOS_CLASS_DEFAULT DISPATCH_QUEUE_PRIORITY_LOW: QOS_CLASS_UTILITY DISPATCH_QUEUE_PRIORITY_BACKGROUND: QOS_CLASS_BACKGROUND 第二个参数:保留参数 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); }); }
调度组
/* 应用场景 开发的时候出现多个网络请求(每个网络请求的时间长短不必定),都完成之后,在统一通知用户 例如:下载小说:三国演义 西游记 金x梅 **/ // 实例化一个调度组 dispatch_group_t group = dispatch_group_create(); // 队列 dispatch_queue_t queue = dispatch_get_global_queue(0, 0); // 任务添加到队列 dispatch_group_async(group, queue, ^{ NSLog(@"下载小说A%@", [NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ NSLog(@"下载小说b%@", [NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ NSLog(@"下载小说x%@", [NSThread currentThread]); }); // 得到全部调度组里面的异步任务完成的通知(能够跨队列通讯) dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // 在主线程更新UI NSLog(@"下载完成,请观看%@", [NSThread currentThread]); });
一次性执行
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self once]; } #pragma mark - 一次性执行 - (void)once { static dispatch_once_t onceToken; NSLog(@"%ld", onceToken); dispatch_once(&onceToken, ^{ NSLog(@"%ld", onceToken); NSLog(@"真的只会执行一次么?"); }); NSLog(@"完成"); }
运行结果
2016-05-30 17:34:57.939 GCD[29725:464402] 0 2016-05-30 17:34:57.940 GCD[29725:464402] 140734769974144 2016-05-30 17:34:57.940 GCD[29725:464402] 真的只会执行一次么? 2016-05-30 17:34:57.940 GCD[29725:464402] 完成 2016-05-30 17:34:59.898 GCD[29725:464402] -1 2016-05-30 17:34:59.898 GCD[29725:464402] 完成 2016-05-30 17:35:00.690 GCD[29725:464402] -1 2016-05-30 17:35:00.690 GCD[29725:464402] 完成 2016-05-30 17:35:01.090 GCD[29725:464402] -1 2016-05-30 17:35:01.091 GCD[29725:464402] 完成 2016-05-30 17:35:02.146 GCD[29725:464402] -1 2016-05-30 17:35:02.147 GCD[29725:464402] 完成