---恢复内容开始---

GCD

GCD的优势

  GCD是苹果公司为多核的并行运算提出的解决方案

  GCD会自动利用更多的CPU内核(比如双核、四核)

GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
GCD中的核心概念
  任务  --存放执行的事情
  队列 --存放任务
GCD的执行:

  • GCD会自动将队列中的任务取出,放到对应的线程中执行
  • 任务的取出遵循队列的FIFO原则:先进先出,后进后出
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
/********************************创建串行queue队列********************************/
DISPATCH_QUEUE_SERIAL这里换成NULL也是创建串行队列
dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
/********************************第一次向queue添加任务********************************/for (int i = 0; i<3; i++) {NSLog(@"A------%@", [NSThread currentThread]);}for (int i = 0; i<3; i++) {NSLog(@"B------%@", [NSThread currentThread]);}});dispatch_async(queue, ^{
/********************************第二次向queue添加任务********************************/for (int i = 0; i<3; i++) {NSLog(@"C------%@", [NSThread currentThread]);}for (int i = 0; i<3; i++) {NSLog(@"D------%@", [NSThread currentThread]);}});dispatch_release(queue);NSLog(@"E--------%@", [NSThread currentThread]);
}

输出结果:

2016-03-29 21:28:50.991 test1[1021:62256] E--------<NSThread: 0x7fcaa0601a00>{number = 1, name = main}
2016-03-29 21:28:50.991 test1[1021:62291] A------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.992 test1[1021:62291] A------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.992 test1[1021:62291] A------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.992 test1[1021:62291] B------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.993 test1[1021:62291] B------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.993 test1[1021:62291] B------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.993 test1[1021:62291] C------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.993 test1[1021:62291] C------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.993 test1[1021:62291] C------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.994 test1[1021:62291] D------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.994 test1[1021:62291] D------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.994 test1[1021:62291] D------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}

上面两句话结合代码分析:就是当我们把我们要做的事情(任务)添加进一个队列中,可能我们分多次添加,上面的代码中我是跟两次在queue队列中添加任务,当GCD把queue队列中的任务取出放到对应的线程中执行的时候, 它会遵守FIFO(先进先出的原则),先执行第一次添加的任务(输出A B),然后执行第二次添加的任务(输出C D),为什么输出结果中会首先输出E呢? 因为这里执行的异步函数执行任务,不会阻塞线程 (下面会讲异步函数) 串行队列 + 异步执行函数会开启一条子线程

注意:上面的案例是在MRC中,所以通过creat创建出来的队列,需要release!

GCD队列的创建以及类型   

/********************************创建串行queue队列********************************/dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);

/********************************创建并发queue队列********************************/dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);

串行队列:队列中的任务执行的方式:任务一个接着一个的执行(一个执行完毕以后,在执行下一个任务)

并发队列:当GCD取出队列中的任务的时候,执行的方式:如果是异步执行的方式的执行下,自动开启多个线程同时执行任务)

将上面的案例中的队列更改成并发队列,我们分析下结果:

/********************************创建并发queue队列********************************/dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue, ^{/********************************第一次向queue添加任务********************************/for (int i = 0; i<3; i++) {NSLog(@"A------%@", [NSThread currentThread]);}for (int i = 0; i<3; i++) {NSLog(@"B------%@", [NSThread currentThread]);}});dispatch_async(queue, ^{/********************************第二次向queue添加任务********************************/for (int i = 0; i<3; i++) {NSLog(@"C------%@", [NSThread currentThread]);}for (int i = 0; i<3; i++) {NSLog(@"D------%@", [NSThread currentThread]);}});dispatch_release(queue);NSLog(@"E--------%@", [NSThread currentThread]);

输出结果:

2016-03-29 21:48:37.056 test1[1043:68365] E--------<NSThread: 0x7fd838402780>{number = 1, name = main}
2016-03-29 21:48:37.056 test1[1043:68403] C------<NSThread: 0x7fd838601ed0>{number = 2, name = (null)}
2016-03-29 21:48:37.056 test1[1043:68404] A------<NSThread: 0x7fd83843b470>{number = 3, name = (null)}
2016-03-29 21:48:37.056 test1[1043:68404] A------<NSThread: 0x7fd83843b470>{number = 3, name = (null)}
2016-03-29 21:48:37.056 test1[1043:68403] C------<NSThread: 0x7fd838601ed0>{number = 2, name = (null)}
2016-03-29 21:48:37.057 test1[1043:68404] A------<NSThread: 0x7fd83843b470>{number = 3, name = (null)}
2016-03-29 21:48:37.057 test1[1043:68403] C------<NSThread: 0x7fd838601ed0>{number = 2, name = (null)}
2016-03-29 21:48:37.057 test1[1043:68404] B------<NSThread: 0x7fd83843b470>{number = 3, name = (null)}
2016-03-29 21:48:37.057 test1[1043:68403] D------<NSThread: 0x7fd838601ed0>{number = 2, name = (null)}
2016-03-29 21:48:37.057 test1[1043:68404] B------<NSThread: 0x7fd83843b470>{number = 3, name = (null)}
2016-03-29 21:48:37.057 test1[1043:68403] D------<NSThread: 0x7fd838601ed0>{number = 2, name = (null)}
2016-03-29 21:48:37.058 test1[1043:68404] B------<NSThread: 0x7fd83843b470>{number = 3, name = (null)}
2016-03-29 21:48:37.058 test1[1043:68403] D------<NSThread: 0x7fd838601ed0>{number = 2, name = (null)}

结果分析:第一行依然输出的是E;因为我们执行任务的方式是异步函数,所以不会堵塞线程,输出的是E,但是这次由于我们创建的队列是并发的,当GCD从队列中取出任务的时候,会自动创建多个线程(根据CPU资源创建),不仅从输出的结果可以看出,创建多条线程,并且执行的任务的时候没有顺序的,说明是并发执行任务的

下面我们看一下同步函数执行任务 + 串行队列 或者 并发队列是什么结果呢

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{/********************************创建异步queue队列********************************/dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);dispatch_sync(queue, ^{/********************************第一次向queue添加任务********************************/for (int i = 0; i<3; i++) {NSLog(@"A------%@", [NSThread currentThread]);}for (int i = 0; i<3; i++) {NSLog(@"B------%@", [NSThread currentThread]);}});/********************************同步方式执行********************************/dispatch_sync(queue, ^{/********************************第二次向queue添加任务********************************/for (int i = 0; i<3; i++) {NSLog(@"C------%@", [NSThread currentThread]);}for (int i = 0; i<3; i++) {NSLog(@"D------%@", [NSThread currentThread]);}});dispatch_release(queue);NSLog(@"E--------%@", [NSThread currentThread]);
}

输出结果

2016-03-29 22:04:22.972 test1[1122:74978] A------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.972 test1[1122:74978] A------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.973 test1[1122:74978] A------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.973 test1[1122:74978] B------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.973 test1[1122:74978] B------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.973 test1[1122:74978] B------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.973 test1[1122:74978] C------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.973 test1[1122:74978] C------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.974 test1[1122:74978] C------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.974 test1[1122:74978] D------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.974 test1[1122:74978] D------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.974 test1[1122:74978] D------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.974 test1[1122:74978] E--------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}

输出的结果:当执行任务的方式采用的是同步执行的时候,不管是串行队列,还是并发队列,都不会开启子线程<也就是说,并发队列只在异步函数执行任务中会有效(创建子线程), E输出在最后输出,整体发现,任务是在主线程执行,并且任务是按着循序执行的,也就是说同步函数会阻塞线程!

全局队列

全局并发队列 

  GCD默认已经提供了全局的并发队列,供整个应用使用,可以无需手动创建

/***  <#Description#>**  @param identifier#> 队列的优先级 一般也传0*  @param flags#>     此参数暂时无用,用0即可* 全局并发队列的优先级#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台*/dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

全局主队列

  主队列是GCD自带的一种特殊的串行队列
使用dispatch_get_main_queue()获得主队列
dispatch_queue_t queue = dispatch_get_main_queue();

线程之间通信

从子线程回到主线程
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// 执行耗时的异步操作...dispatch_async(dispatch_get_main_queue(), ^{// 回到主线程,执行UI刷新操作});
});

在开发中GCD的其他常用API接口

延时执行

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{[self performSelector:@selector(task) withObject:nil afterDelay:2.0];
}- (void)task
{NSLog(@"延迟2秒执行---%@", [NSThread currentThread]);
}

输出结果

2016-03-29 22:29:43.308 test1[1153:84643] 延迟2秒执行---<NSThread: 0x7fa682e005e0>{number = 1, name = main}

结果分析:延迟两秒执行task方法,在task所在的线程是主线程

一次性代码

使用dispatch_once函数能保证某段代码在程序运行过程中只被执行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{// 只执行1次的代码(这里面默认是线程安全的)
});

  在整个程序中,只会执行一次,开发中可用于单例

单例模式

单例模式的作用
可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问
从而方便地控制了实例个数,并节约系统资源
单例模式的使用场合
在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次)

ARC中,单例模式的实现
在.m中保留一个全局的static的实例
static id _instance;重写allocWithZone:方法,在这里创建唯一的实例(注意线程安全)
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{_instance = [super allocWithZone:zone];});return _instance;
}

提供1个类方法让外界访问唯一的实例
+ (instancetype)sharedInstance
{static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{_instance = [[self alloc] init];});return _instance;
}实现copyWithZone:方法
- (id)copyWithZone:(struct _NSZone *)zone
{return _instance;
}

快速迭代

// 使用dispatch_apply函数能进行快速迭代遍历NSArray *array = @[@"coder_hong", @"zhangsan", @"lishi"];NSUInteger count = array.count;dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t index){// 执行10次代码,index顺序不确定NSLog(@"%@", array[index]);});

输出结果:

2016-03-29 22:45:47.886 test1[1228:91621] coder_hong
2016-03-29 22:45:47.886 test1[1228:91661] lishi
2016-03-29 22:45:47.886 test1[1228:91657] zhangsan

转载于:https://www.cnblogs.com/mshong/p/5334890.html

多线程--GCD的基本用法相关推荐

  1. C#多线程中lock的用法

    最近在看些c#的代码,发现很多是以前没有接触到了,只能上网查,把比较好的整理下来. 经常碰到同时需要对某个数据进行操作,或者对某个文件进行读写操作,对于这些操作我们以前往往不能很好的进行处理,自从C# ...

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

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

  3. 多线程中Condition的用法

    多线程中Condition的用法与Object中wait.notify.notifyAll用法非常的相似 Condition与Lock对象搭配完成等待唤醒机制 首先我们需要创建Condition对象 ...

  4. swift 多线程GCD和延时调用

    GCD 是一种非常方便的使用多线程的方式.通过使用 GCD,我们可以在确保尽量简单的语法的前提下进行灵活的多线程编程.在 "复杂必死" 的多线程编程中,保持简单就是避免错误的金科玉 ...

  5. iOS多线程GCD 研究

    Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法. dispatch queue分成以下三种: 1)运行在主线程的Main queue,通过dispat ...

  6. Swift - 多线程GCD详解

    //  GCD详解 //  目录: //  1. 创建GCD队列(最常用) //  2. 自定义创建队列 //  3. 使用多线程实现延迟加载 //  4. 使用多线程实现重复(循环) //  5. ...

  7. Java 多线程:synchronized 关键字用法(修饰类,方法,静态方法,代码块)

    前言 在 多线程生成的原因(Java内存模型与i++操作解析) 中,介绍了Java的内存模型,从而可能导致的多线程问题.synchronized就是避免这个问题的解决方法之一.除了 synchroni ...

  8. IOS开发之多线程 -- GCD的方方面面

    前言:这篇GCD的博文是本人阅读了很多海内外大神的关于GCD的文章,以及结合之前自己对GCD的粗浅的认识,然后取其精华,去其槽粕,综合起来的笔记,而且是尽可能的以通熟易懂的并且是正确的理论论述方式呈现 ...

  9. iOS 多线程GCD

    为了了解.记忆更深刻,记录下,后面也会附上自己git 上demo,欢迎互相学习!! 一:什么是GCD GCD本身是苹果公司为多核的并行运算提出的解决方案.GCD在工作时会自动利用更多的处理器核心,以充 ...

最新文章

  1. Lock接口Condition,以及Lock与synchronized异同
  2. localdatetime 获取天_LocalDateTime的一些用法
  3. C++编译过程中没有找到MFC80UD.DLL,因此这个程序未能启动.重新安装应用程序可能会修复此问题? 的彻底解决...
  4. System76 是如何打造开源硬件的
  5. 2021 年百度之星·程序设计大赛 - 初赛三
  6. 【转载】SNMPv3 配置及snmpwalk命令信息获取
  7. jquery 移动端 ui 组件库 移动端前端UI库—Frozen UI、SUI Mobile、light7、WeUI、jqweui
  8. Linux(ubuntu18.04)安装eclipse教程
  9. macOS中显示按键操作
  10. 圣诞节苹果服务器没有人维护2020,2020圣诞节真的推迟到1月8号吗
  11. magedu第一天学习(计算机基础部分)
  12. 解读 2022 诺贝尔生理学或医学奖 | MedChemExpress
  13. mysql 主从1146_mysql 主从复制1146错误处理办法
  14. i3cpu驱动xp_Intel英特尔 Core i3/Core i5/Core i7系列CPU显示驱动 14.46.9.5394版 For XP-64
  15. 金属结构保温板的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  16. html自动刷新 idea,idea新建css idea怎么刷新导入的css
  17. 连接数据库——模拟ATM机查、存、取、开户功能
  18. 代码大全(读书笔记)
  19. vue2对应的常用插件版本
  20. sqlite 表的列增加,修改,删除及表的重构和去重操作

热门文章

  1. SpringBoot 搭建
  2. DotNetBar的使用—(界面风格)
  3. 关于self.用法的一些总结
  4. 转载 .net面试题大全(有答案)
  5. 家用计算机键盘图,电脑键盘示意图,详细教您如何正确的使用键盘
  6. salesforce bigobject 的限制_苹果进一步限制第三方维修
  7. 用 Flask 来写个轻博客 (26) — 使用 Flask-Celery-Helper 实现异步任务
  8. 设置stm32系统各部分时钟
  9. Android异步消息处理机制
  10. form 提交多个对象及springMVC接收