多线程 (四)GCD
学习GCD要掌握几个概念
任务:需要执行的代码块可以看作一个任务
队列:把任务放到队列里,遵循先进先出的原则
队列又分为串行队列和并行队列
串行队列:顺序执行
并发队列:同时执行多个任务
同步:在当前线程执行 (不开辟新线程)
异步:在另一条线程执行(会开辟新线程)
gcd是支持arc的,不用我们进行内存管理
1.串行队列,同步添加一个任务(这个操作其实没有什么意义,这里仅仅作一个示例)
- (void)serialQueueSync
{
//1.创建串行队列,注意:第一个参数为队列标识C语言前面不用带@
dispatch_queue_t queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL); //2.同步执行任务
//一般只要向串行队列添加同步任务,会马上执行
dispatch_sync(queue, ^{ NSLog(@"这是一个同步任务,在线程:%@中执行",[NSThread currentThread]); });
}
2.串行队列,异步添加一个任务
- (void)serialQueueAsync
{
//1.创建串行队列,注意:第一个参数为队列标识C语言前面不用带@
dispatch_queue_t queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL); //2.异步执行任务
dispatch_async(queue, ^{ NSLog(@"这是一个异步任务,在线程:%@中执行",[NSThread currentThread]); });
}
下面我们用一个for循环来理解串行队列和并发队列的区别
串行队列
- (void)serial
{
dispatch_queue_t queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
//异步执行任务
for(int i = 0; i < 5; i++)
{
dispatch_async(queue, ^{ NSLog(@"这是一个异步任务,i = %d ,在线程:%@中执行",i,[NSThread currentThread]); });
}
}
结果可以看到只开辟了一个线程,所有任务排队在这个线程里执行

并发队列
- (void)concurrent
{
//并发队列
dispatch_queue_t queue = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
//异步执行任务
for(int i = 0; i < 5; i++)
{
dispatch_async(queue, ^{ NSLog(@"这是一个异步任务,i = %d,在线程:%@中执行",i,[NSThread currentThread]); });
}
}
结果可以看到开辟了多条线程同时执行任务

并发队列同步执行:不会开辟新线程
- (void)concurrentSync
{
//并发队列
dispatch_queue_t queue = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
//同步执行任务
for(int i = 0; i < 5; i++)
{
dispatch_sync(queue, ^{ NSLog(@"这是一个异步任务,i = %d ,在线程:%@中执行",i,[NSThread currentThread]); });
}
}
总结:同步异步决定了要不要开启新线程,串行和并发决定任务的执行方式
- 同步:不具备开辟线程的能力
- 异步:能开辟新线程
- 并发:多个任务并发(同时)执行
- 串行:按顺序执行任务
串行队列同步执行:不开新线程,在原来线程里面顺序执行
串行队列异步执行:开一条新线程,在新线程里顺序执行
并发队列异步执行:开多条线程(我们并不能控制开启多少条线程,由GCD底层帮我们完成),并发执行任务
并发队列同步执行:不开线程,在原来线程里顺序执行
可以看出,串行队列同步执行和并发队列同步执行对多线程来说没有什么实际意义,开发中也基本不会这么去用
主队列
1.当程序启动时,就会创建一个主线程,同时有一个主队列(iOS开发中默认UI更新全在主线程中完成)
2.主队列负责在主线程上调度任务
3.异步添加任务到主队列不会开启新线程,任务在主线程中执行
4.异步添加到主队列的任务并不一定马上执行,而是顺序等待任务执行
5.同步添加任务到主队列,这是一种十分愚蠢的做法,永远不要这么去做,下面会做说明
下面的代码能帮助我们理解
异步添加任务到主队
- (void)mainQueue
{
//获取主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
for (int i = 0; i < 5; i++)
{
NSLog(@"添加第%d个任务",i);
//异步添加
dispatch_async(mainQueue, ^{
NSLog(@"i = %d thread = %@",i,[NSThread currentThread]);
});
}
}
打印结果可以看出任务全部添加了之后才顺序执行

同步添加任务到主队列 (不要这么做,这里仅做示例)
- (void)mainQueue
{
//获取主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
for (int i = 0; i < 5; i++)
{
NSLog(@"添加第%d个任务",i);
//同步添加
dispatch_sync(mainQueue, ^{
NSLog(@"i = %d thread = %@",i,[NSThread currentThread]);
});
}
}
从打印结果我们能发现主线程被阻塞了(在view上面添加一些UI控件能更清楚的发现这一点),出现这种情况的原因是:同步任务需要马上执行,但是主线程正在执行添加任务,此时添加任务又在等待同步任务执行完成,就造成了互相等待的局面,阻塞了主线程,造成死锁(死锁的概念可以看我的另一篇博文iOS中的锁)

全局队列
全局队列和并发队列的区别(这两种队列用法相似)
1.全局队列没有标示,并发队列有
2.全局队列供所有应用程序使用
3.MRC中,并发队列需要我们进行内存管理,全局队列不需要
//获得全局队列,第一个参数是指队列的服务质量(优先级)一般使用默认0,第二个参数是保留参数也填0
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
线程间的通信(当我们在其他线程中做完数据处理,想把这些数据显示到界面的时候,就要进行线程间通信,iOS默认更新UI的操作都在主线程中执行)
- (void)communicate
{
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(globalQueue, ^{
//在这里进行异步操作
dispatch_async(mainQueue, ^{
//回到主线程更新UI
});
});
}
延迟执行(下例本质是延迟5s把任务添加到队列)
几个参数的含义
dispatch_time(何时, 经过多少纳秒)
NSEC_PER_SEC :1000000000ull
所以我们要使用3 * NSEC_PER_SEC:这样才算3秒
- (void)delay
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"这个任务延迟5s执行");
});
}
调度组 (应用场景:多个任务全部完成了,再统一通知用户,通过轮询机制判断所有组里的任务是否完成)
- (void)group
{
//创建一个调度组
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_queue_t mainQueue = dispatch_get_main_queue(); //创建多个任务
dispatch_group_async(group, globalQueue, ^{ [NSThread sleepForTimeInterval:1];
NSLog(@"任务1完成");
});
dispatch_group_async(group, globalQueue, ^{ [NSThread sleepForTimeInterval:3];
NSLog(@"任务2完成");
});
dispatch_group_async(group, globalQueue, ^{ [NSThread sleepForTimeInterval:2];
NSLog(@"任务3完成");
}); //获得组里面所有任务的完成通知
dispatch_group_notify(group, mainQueue, ^{
NSLog(@"所有任务完成");
}); }
dispatch_once(只执行一次,受线程保护,常用来设计单例)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self once];
[self once];
} - (void)once
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"只会执行一次");
}); NSLog(@"可以执行多次");
}
多线程 (四)GCD的更多相关文章
- iOS开发多线程篇—GCD介绍
iOS开发多线程篇—GCD介绍 一.简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 G ...
- [iOS]多线程和GCD
新博客wossoneri.com 进程和线程 进程 是指在系统中正在运行的一个应用程序. 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内. 比如同时打开QQ.Xcode,系统就会分别 ...
- iOS开发多线程篇—GCD简介
iOS开发多线程篇—GCD介绍 一.简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 G ...
- iOS 开发多线程篇—GCD的常见用法
iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...
- iOS开发多线程篇—GCD的基本使用
iOS开发多线程篇—GCD的基本使用 一.主队列介绍 主队列:是和主线程相关联的队列,主队列是GCD自带的一种特殊的串行队列,放在主队列中得任务,都会放到主线程中执行. 提示:如果把任务放到主队列中进 ...
- iOS开发多线程篇—GCD的常见用法
iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...
- java 多线程四
java 多线程一 java 多线程二 java 多线程三 java 多线程四 一个生产者,消费者的例子: import java.util.Stack; /** * Created by root ...
- swift 多线程及GCD
1.基本概念 1)进程: 进程是指在系统中正在运行的一个应用程序.每个进程之间是独立的,每个进程运行在其专用且受保护的内存空间里.某进程内的线程在其它进程不可见 2)线程: 1个进程要执行任务,必须有 ...
- 多线程编程 - GCD(转)
原文:http://blog.csdn.net/q199109106q/article/details/8566300 一.简介 在iOS所有实现多线程的方案中,GCD应该是最有魅力的,因为GCD本身 ...
- 网络与多线程---OC中多线程方法GCD(二)
小编在前一篇中介绍了多线程实现的五种常用方法.在接下来所介绍的这种方法是最具有魅力的,最具有诱惑的实现多线程的方案---GCD 一.什么是GCD GCD是Grand Central Dispatch的 ...
随机推荐
- [SWF]在线预览文档下载
写本文的缘由:领导有些项目文档需要审阅,网站上的文档只能在线预览,没有提供下载.开始用截屏的方式,可想而知这将会是多大的重复性劳动.所以研究了一下,发现可以曲线救国,所以在这里分享一下. 问题描述:这 ...
- 关于delete
上面三图在debug下,delete的时候会以fe ee覆盖指针所指向要回收内存前后较大一块区域的值. 下图对于release下delete的时候会先用fe ee覆盖指针所指位置起6*4=24字节, ...
- windows github 搭建与使用
git/github使用以下是全部在命令行使用(windows/github) 注册账户以及创建仓库先在github建立账号和创建仓库,此时为空的仓库 配置git下载并安装 git windows版本 ...
- ASP.NET文件上传的三种基本方法
ASP.NET依托.net framework类库,封装了大量的功能,使得上传文件非常简单,主要有以下三种基本方法. 方法一:用Web控件FileUpload,上传到网站根目录. <form i ...
- mysql实例---sql语句中使用@变量
本文介绍下,在mysql语句中使用@变量的一个例子,学习下这个特殊变量的用法,有需要的朋友参考下吧. 要求: 计算用户距上次访问的天数,根据imei号区分不同的用户,如果时间段内只有一次访问则为0. ...
- apache-2.4.12之虚拟主机配置问题与觖决办法
apache-2.4.12基于域名访问的多虚拟主机配置 原始配置: <VirtualHost *:80> ServerAdmin kk@etiantian.org DocumentRoot ...
- Android SDK离线安装方法详解(加速安装) 转
AndroidSDK在国内下载一直很慢··有时候通宵都下不了一点点,最后只有选择离线安装,现在发出离线安装地址和方法,希望对大家有帮助! 离线安装包下载地址:http://dl.vmall.com/c ...
- 2014年辛星完全解读Javascript第七节 数组和对象
由于Javascript是脚本语言,因此,使用起来非常方便,数组的使用也是比较简单的,下面我们就主要介绍一下Javascript中数组的介绍,以及上一节中没有完成的对象的介绍. *********** ...
- oracle 导入报错 ORA-00959: tablespace 'HB' does not exist
导入oracle 时发现有几张表导入时一直报错: 报错信息:IMP-00003: ORACLE error 959 encountered ORA-00959: tablespace 'HB' d ...
- 新的MOVE结构,和在项目中实际的感受
关于MVC/MVP的瑕疵 MVC 和 MVP是最简单,最脍炙人口的框架结构. 有一段时间, 凡事有一定规模的代码,我都会架在上面,甚至后台程序也不例外(预留出可以注册的用户交互接口,作为后台控制器). ...