一、什么是GCD

GCD:grand central dispatch 牛逼的中枢调度器
特点:
1.纯C语言API
2.apple官方出品
3.自动管理生命周期(ARC中)
4.只需要告诉GCD需要执行的任务,操作简单

二、GCD的使用

1、队列的使用和创建

队列:存放需要执行的任务的容器。而执行这些任务的是线程。队列不一定创建线程,如果不创建线程,则当前线程来执行这些队列中的任务。

创建串行队列

    /**创建队列@param "concurrentQueue" 队列名称@param DISPATCH_QUEUE_CONCURRENT 队列类型,CONCURRENT为并发队列,NULL为串行队列@return 队列*/dispatch_queue_t t3 = dispatch_queue_create("serialQueue", NULL);

获取全局并发队列

    /**直接获取全局并发队列@param QOS_CLASS_DEFAULT 优先级别,有两种方式表示,详见API官方注释@param 0 预留参数,传0@return 全局并发队列*/dispatch_queue_t t1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

创建并发队列

    /**创建队列@param "concurrentQueue" 队列名称@param DISPATCH_QUEUE_CONCURRENT 队列类型,CONCURRENT为并发队列,NULL为串行队列@return 队列*/dispatch_queue_t t2 = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
2、执行任务

任务的执行步骤:创建任务和队列后,将任务添加到队列中,最后根据asyn和syn来判断是否需要创建线程以及在哪个线程执行

异步执行队列中的任务

dispatch_async(queue, ^{NSLog(@"1---%@",[NSThread currentThread]);});

同步执行队列中的任务

dispatch_sync(queue, ^{NSLog(@"1---%@",[NSThread currentThread]);});

三、四种情况

1、串行队列同步执行
- (void)syncTaskWithSerialQueue {NSLog(@"syncTaskWithSerialQueue---start");dispatch_queue_t queue = dispatch_queue_create("serialQueue", NULL);dispatch_sync(queue, ^{sleep(1);NSLog(@"1---%@",[NSThread currentThread]);});dispatch_sync(queue, ^{sleep(1);NSLog(@"2---%@",[NSThread currentThread]);});dispatch_sync(queue, ^{sleep(1);NSLog(@"3---%@",[NSThread currentThread]);});dispatch_sync(queue, ^{sleep(1);NSLog(@"4---%@",[NSThread currentThread]);});NSLog(@"syncTaskWithSerialQueue---end");
}

结果:

2018-11-21 15:25:03.037 XKQuote[51245:4129046] syncTaskWithSerialQueue---start
2018-11-21 15:25:04.037 XKQuote[51245:4129046] 1---<NSThread: 0x7f974a502b80>{number = 1, name = main}
2018-11-21 15:25:05.038 XKQuote[51245:4129046] 2---<NSThread: 0x7f974a502b80>{number = 1, name = main}
2018-11-21 15:25:06.040 XKQuote[51245:4129046] 3---<NSThread: 0x7f974a502b80>{number = 1, name = main}
2018-11-21 15:25:07.040 XKQuote[51245:4129046] 4---<NSThread: 0x7f974a502b80>{number = 1, name = main}
2018-11-21 15:25:07.041 XKQuote[51245:4129046] syncTaskWithSerialQueue---end

总结:
1.串行队列中同步执行任务不会创建线程,在当前线程中执行
2.顺序执行
3.阻塞当前线程
4.同步执行会等待当前队列中的任务执行完毕,才会接着执行

2、串行队列异步执行
- (void)asyncTaskWithSerialQueue {NSLog(@"asyncTaskWithSerialQueue---start");dispatch_queue_t queue = dispatch_queue_create("serial2", NULL);dispatch_async(queue, ^{sleep(1);NSLog(@"asyncTaskWithSerialQueue:1---%@",[NSThread currentThread]);});dispatch_async(queue, ^{sleep(1);NSLog(@"asyncTaskWithSerialQueue:2---%@",[NSThread currentThread]);});dispatch_async(queue, ^{sleep(1);NSLog(@"asyncTaskWithSerialQueue:3---%@",[NSThread currentThread]);});dispatch_async(queue, ^{sleep(1);NSLog(@"asyncTaskWithSerialQueue:4---%@",[NSThread currentThread]);});NSLog(@"asyncTaskWithSerialQueue---end");
}

结果

2018-11-22 15:01:42.505 XKQuote[14265:4858578] asyncTaskWithSerialQueue---start
2018-11-22 15:01:42.506 XKQuote[14265:4858578] asyncTaskWithSerialQueue---end
2018-11-22 15:01:43.510 XKQuote[14265:4858727] asyncTaskWithSerialQueue:1---<NSThread: 0x7fd6775a3400>{number = 2, name = (null)}
2018-11-22 15:01:44.514 XKQuote[14265:4858727] asyncTaskWithSerialQueue:2---<NSThread: 0x7fd6775a3400>{number = 2, name = (null)}
2018-11-22 15:01:45.518 XKQuote[14265:4858727] asyncTaskWithSerialQueue:3---<NSThread: 0x7fd6775a3400>{number = 2, name = (null)}
2018-11-22 15:01:46.523 XKQuote[14265:4858727] asyncTaskWithSerialQueue:4---<NSThread: 0x7fd6775a3400>{number = 2, name = (null)}

总结
1.开启了线程,但是只开启了一个;
2.所有任务都在开启的那个线程中按顺序执行

3、并行队列同步执行
- (void)syncTaskWithConcurrentQueue {NSLog(@"syncTaskWithConcurrentQueue---begin");dispatch_queue_t queue = dispatch_queue_create("concurrent1", DISPATCH_QUEUE_CONCURRENT);
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_sync(queue, ^{NSLog(@"syncTaskWithConcurrentQueue:1---%@",[NSThread currentThread]);});dispatch_sync(queue, ^{NSLog(@"syncTaskWithConcurrentQueue:2---%@",[NSThread currentThread]);});dispatch_sync(queue, ^{NSLog(@"syncTaskWithConcurrentQueue:3---%@",[NSThread currentThread]);});dispatch_sync(queue, ^{NSLog(@"syncTaskWithConcurrentQueue:4---%@",[NSThread currentThread]);});NSLog(@"syncTaskWithConcurrentQueue---end");
}

结果

2018-11-22 15:05:25.698 XKQuote[14338:4863404] syncTaskWithConcurrentQueue---begin
2018-11-22 15:05:26.700 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:1---<NSThread: 0x7fa141d05210>{number = 1, name = main}
2018-11-22 15:05:27.701 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:2---<NSThread: 0x7fa141d05210>{number = 1, name = main}
2018-11-22 15:05:28.702 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:3---<NSThread: 0x7fa141d05210>{number = 1, name = main}
2018-11-22 15:05:29.703 XKQuote[14338:4863404] syncTaskWithConcurrentQueue:4---<NSThread: 0x7fa141d05210>{number = 1, name = main}
2018-11-22 15:05:29.704 XKQuote[14338:4863404] syncTaskWithConcurrentQueue---end

总结
1.并行队列中同步执行不会创建新的线程;
2.在当前线程中顺序执行,会阻塞线程;
3.并发的前提是多线程
4.同步执行会等待当前队列中的任务执行完毕,才会接着执行

4、并行队列异步执行
- (void)asyncTaskWithConcurrentQueue {NSLog(@"asyncTaskWithSerialQueue---start");dispatch_queue_t queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue, ^{sleep(1);NSLog(@"1---%@",[NSThread currentThread]);});dispatch_async(queue, ^{sleep(1);NSLog(@"2---%@",[NSThread currentThread]);});dispatch_async(queue, ^{sleep(1);NSLog(@"3---%@",[NSThread currentThread]);});dispatch_async(queue, ^{sleep(1);NSLog(@"4---%@",[NSThread currentThread]);});NSLog(@"syncTaskWithSerialQueue---end");
}
2018-11-21 16:11:31.372 XKQuote[51304:4131596] asyncTaskWithSerialQueue---start
2018-11-21 16:11:31.372 XKQuote[51304:4131596] syncTaskWithSerialQueue---end
2018-11-21 16:11:32.372 XKQuote[51304:4183129] 1---<NSThread: 0x7fdff3504af0>{number = 6, name = (null)}
2018-11-21 16:11:32.372 XKQuote[51304:4187339] 2---<NSThread: 0x7fdff372f090>{number = 7, name = (null)}
2018-11-21 16:11:32.373 XKQuote[51304:4187341] 4---<NSThread: 0x7fdff342dd80>{number = 8, name = (null)}
2018-11-21 16:11:32.373 XKQuote[51304:4187340] 3---<NSThread: 0x7fdff3413a40>{number = 9, name = (null)}

总结
1.并行队列异步执行创建了新的队列(具体创建几个队列由GCD自己控住)
2.不阻塞当前线程;
3.不是顺序执行(对比:gropu,优先级)

大总结
sync+serial = sync + concurrent
async+serial:新开一个线程顺序执行
async+concurrent:新开多个线程异步执行
并发的前提是多线程
并发和串行是相对于队列来说的,指的是队列中任务的执行顺序,同步和异步针对的是任务执行是否需要立即返回返回值
同步执行会等待当前队列中的任务执行完毕,才会接着执行后面的代码

四、两种特殊情况

主线程中同步执行
- (void)mainQueueSyncTask {NSLog(@"mainQueueSyncTask---start");dispatch_queue_t t = dispatch_get_main_queue();dispatch_sync(t, ^{NSLog(@"1---%@",[NSThread currentThread]);});dispatch_sync(t, ^{NSLog(@"2---%@",[NSThread currentThread]);});dispatch_sync(t, ^{NSLog(@"3---%@",[NSThread currentThread]);});dispatch_sync(t, ^{NSLog(@"4---%@",[NSThread currentThread]);});NSLog(@"mainQueueSyncTask---end");
}

结果:

2018-11-22 15:54:56.523 XKQuote[14542:4908219] mainQueueSyncTask---start

原因:
线程是执行任务的,队列是存放任务的。当主线程执行完主队列中的ABCD...等,走到mainQueueSyncTask方法时,mainQueueSyncTask就相当于主线程正在处理的一个任务,而此时执行到dispatch_sync,此时会在主队列中添加一个任务,暂成为newTask,也就是排在mainQueueSyncTask后面的任务,而同步执行需要马上执行任务,而主线程现在正在执行mainQueueSyncTask这个方法,所以dispatch_sync在等待主线程。而主线程在执行mainQueueSyncTask方法中的dispatch_sync这一步,只有这一步返回了结果,mainThread才会继续往下执行到NSLog(@"end")结束,再去执行newTask,所以形成了相互的等待;

步骤简析:
1.mainQueueSyncTask执行NSLog完毕
2.执行dispatch_sync(),未返回,等待主线程执行后返回结果
3.主队列等待dispatch_sync()返回后执行mainQueueSyncTask方法中的下一步
4.循环等待

换各种方法:

   dispatch_queue_t t = dispatch_queue_create("serialQueue", 0);
//    dispatch_queue_t t = dispatch_get_main_queue();NSLog(@"%@",[NSThread currentThread]);dispatch_sync(t, ^{NSLog(@"%@",[NSThread currentThread]);});NSLog(@"xxx");

结果:

2019-06-15 07:04:51.450024+0800 XKSqlite3[64298:2020687] <NSThread: 0x600002792e80>{number = 1, name = main}
2019-06-15 07:04:51.450251+0800 XKSqlite3[64298:2020687] <NSThread: 0x600002792e80>{number = 1, name = main}
2019-06-15 07:04:55.336086+0800 XKSqlite3[64298:2020687] xxx

注意:
1、注意输出,执行的线程都在主线程;
2、成功执行完成,没有发生堵塞;
原因:
1、队列只是存放任务,dispatch_get_main_queue()也只是获取主队列,而不是主线程。
2、在哪个线程执行,是否新开线程执行这些都是GCD自己控制,队列永远是存放任务的,而线程是执行任务的。
3、任务没有存放在朱队列,就不存在排队等待的情况,所以并不会发生堵塞。

非主线程中在主队列中同步执行任务
- (void)mainQueueSyncTaskInSubThread {// initWithBlock方法在10.0以后再能使用NSThread *thread = [[NSThread alloc] initWithBlock:^{NSLog(@"mainQueueSyncTask---start");NSLog(@"%@",[NSThread currentThread]);dispatch_queue_t t = dispatch_get_main_queue();dispatch_sync(t, ^{NSLog(@"1---%@",[NSThread currentThread]);});dispatch_sync(t, ^{NSLog(@"2---%@",[NSThread currentThread]);});dispatch_sync(t, ^{NSLog(@"3---%@",[NSThread currentThread]);});dispatch_sync(t, ^{NSLog(@"4---%@",[NSThread currentThread]);});NSLog(@"mainQueueSyncTask---end");}];[thread start];
}

结果

2018-11-22 16:05:43.285 XKQuote[14826:4922979] mainQueueSyncTask---start
2018-11-22 16:05:43.286 XKQuote[14826:4922979] <NSThread: 0x600000270300>{number = 4, name = (null)}
2018-11-22 16:05:43.298 XKQuote[14826:4922657] 1---<NSThread: 0x600000075380>{number = 1, name = main}
2018-11-22 16:05:43.299 XKQuote[14826:4922657] 2---<NSThread: 0x600000075380>{number = 1, name = main}
2018-11-22 16:05:43.300 XKQuote[14826:4922657] 3---<NSThread: 0x600000075380>{number = 1, name = main}
2018-11-22 16:05:43.301 XKQuote[14826:4922657] 4---<NSThread: 0x600000075380>{number = 1, name = main}
2018-11-22 16:05:43.302 XKQuote[14826:4922979] mainQueueSyncTask---end

原因:
之所以不循环等待,是执行dispatch_sync时,去到了mainThread执行,而当前thread执行的是mainQueueSyncTaskInSubThread方法,当然不会循环等待。特别注意执行dispatch_sync之前的NSLog,表明当前线程不是主线程

主队列异步执行
- (void)AsyncTaskWithMainQueue {NSLog(@"AsyncTaskWithMainQueue---start");NSLog(@"%@",[NSThread currentThread]);dispatch_queue_t t = dispatch_get_main_queue();dispatch_async(t, ^{NSLog(@"1---%@",[NSThread currentThread]);});dispatch_async(t, ^{NSLog(@"2---%@",[NSThread currentThread]);});dispatch_async(t, ^{NSLog(@"3---%@",[NSThread currentThread]);});dispatch_async(t, ^{NSLog(@"4---%@",[NSThread currentThread]);});NSLog(@"AsyncTaskWithMainQueue---end");
}

结果

2018-11-22 16:20:54.298 XKQuote[17987:4947380] AsyncTaskWithMainQueue---start
2018-11-22 16:20:54.299 XKQuote[17987:4947380] <NSThread: 0x7faa5bc02090>{number = 1, name = main}
2018-11-22 16:20:54.299 XKQuote[17987:4947380] AsyncTaskWithMainQueue---end
2018-11-22 16:20:54.307 XKQuote[17987:4947380] 1---<NSThread: 0x7faa5bc02090>{number = 1, name = main}
2018-11-22 16:20:54.307 XKQuote[17987:4947380] 2---<NSThread: 0x7faa5bc02090>{number = 1, name = main}
2018-11-22 16:20:54.308 XKQuote[17987:4947380] 3---<NSThread: 0x7faa5bc02090>{number = 1, name = main}
2018-11-22 16:20:54.308 XKQuote[17987:4947380] 4---<NSThread: 0x7faa5bc02090>{number = 1, name = main}

原因
主队列异步执行的区别就是异步会直接返回结果,所以执行完方法之后才会去执行dispatch_async

iOS多线程(一):GCD的基本使用相关推荐

  1. iOS 多线程和GCD(Grand Central Dispath) 教程 (一)

    iOS 多线程和GCD(Grand Central Dispath) 教程 (一)  本文翻译自 Ray Wenderlich 的博客 点击打开原文链接.全部由本人亲手翻译...童叟无欺~ 你有木有遇 ...

  2. iOS 多线程 swift5 GCD 自己消化的

    文章目录 1.串行并行,同步异步 1.1 串行队列 + 同步执行 主队列:死锁 自定义串行队列:顺序执行,和正常执行代码一样 1.2 并行队列 + 同步执行:不开启线程,按代码顺序执行 1.3 串行队 ...

  3. iOS多线程-【GCD】

    参考链接:https://www.jianshu.com/p/2d57c72016c6 博主总结的很好,个人理解的很清晰 1.GCD简介 因为 GCD 有很多好处啊,具体如下: GCD 可用于多核的并 ...

  4. IOS多线程使用GCD与信号量实现生产者与消费者模式

    一.原理的简述 在生产者消费者模式当中,首先需要分清在这个模式当中有哪些角色? 各角色分别担任什么职责与它们之间的关系如何? 角色之间是在保证数据的准确性的情况下如何通信(同步数据)的? 假设现在有一 ...

  5. iOS 多线程:『GCD』详尽总结

    原文链接:www.jianshu.com/p/2d57c7201- 感谢大家对这篇文章的喜欢和支持.为了不辜负大家的喜欢,也为了更好的让大家了解 iOS 多线程,以及 GCD 的相关知识,我对这篇文章 ...

  6. iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用(上)

    2017-07-08 remember17 Cocoa开发者社区 目的 本文主要是分享iOS多线程的相关内容,为了更系统的讲解,将分为以下7个方面来展开描述. 多线程的基本概念 线程的状态与生命周期 ...

  7. iOS多线程开发之GCD(基础篇)

    总纲: GCD基本概念 GCD如何实现 GCD如何使用 队列和任务组合 一.GCD基本概念 GCD 全称Grand Central Dispatch(大中枢队列调度),是一套低层API,提供了⼀种新的 ...

  8. iOS 多线程-GCD栅栏方法

    iOS 多线程-GCD任务+队列. iOS 多线程-GCD队列组. iOS 多线程-GCD栅栏方法. 上一篇文章记录了队列组的使用,是为了处理多个任务之间的顺序.但是开发中会出现多组任务的顺序问题. ...

  9. iOS 多线程的四种技术方案

    iOS 多线程的四种技术方案 image pthread 实现多线程操作 代码实现: void * run(void *param) {for (NSInteger i = 0; i < 100 ...

  10. iOS多线程:『NSOperation、NSOperationQueue』详尽总结

    2019独角兽企业重金招聘Python工程师标准>>> iOS多线程:『NSOperation.NSOperationQueue』详尽总结 转载: 原地址https://www.ji ...

最新文章

  1. HANA 数据库备份hang住的解决办法
  2. Java查询spark中生成的文件_java+spark-sql查询excel
  3. r语言如何写入一个excel_R语言如何进行聚类分析?
  4. python中dpi_python matplotlib 绘图 和 dpi对应关系详解
  5. android崩溃日志收集
  6. VTK:Utilities之GetDataRoot
  7. VTK:Filtering之VertexGlyphFilter
  8. vue --- http拦截,登录登出的逻辑设计
  9. WCF与AJAX编程开发实践(1):AJAX基础概念和纯AJAX示例
  10. 机器学习之 特征工程
  11. 进程树--用Enki学Linux系列(18)
  12. MemCache详细介绍
  13. 【Git入门之六】远程仓库
  14. 电信单线实现上网加看电视 HS8145V +K2P华硕固件
  15. GitHub代码,资源下载慢?怎么办?
  16. 天蓝色在ps中的色值_天蓝色事件网格集成测试
  17. CocoaPods 使用小结
  18. Python数据挖掘学习——鸢尾花分类、OneR算法
  19. Unity制作格斗游戏核心思路总结
  20. 数据采集:Flume和Logstash的工作原理和应用场景

热门文章

  1. 【Hoxton.SR1版本】Spring Cloud Eureka服务注册中心集群搭建
  2. uploadify上传文件Firefox浏览器上传失败解决方法
  3. 基于RPM包的LAMP搭建
  4. SpringMVC Redirect 跳转后保存Model中的数据
  5. Android adb shell执行mv等操作时,提示:Read-only file system的解决办法
  6. 岁月是把杀猪刀时光不止催人老
  7. 挑netfilter的11个不足之处
  8. mysql中加号变成空格了_从数据库中读取字符串时其中的空格变成加号
  9. Android进阶(三) 数据存储之SharedPreference
  10. vmware桥接模式、NAT网络地址转换、仅主机模式