学习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的更多相关文章

  1. iOS开发多线程篇—GCD介绍

    iOS开发多线程篇—GCD介绍 一.简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 G ...

  2. [iOS]多线程和GCD

    新博客wossoneri.com 进程和线程 进程 是指在系统中正在运行的一个应用程序. 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内. 比如同时打开QQ.Xcode,系统就会分别 ...

  3. iOS开发多线程篇—GCD简介

    iOS开发多线程篇—GCD介绍 一.简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 G ...

  4. iOS 开发多线程篇—GCD的常见用法

    iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...

  5. iOS开发多线程篇—GCD的基本使用

    iOS开发多线程篇—GCD的基本使用 一.主队列介绍 主队列:是和主线程相关联的队列,主队列是GCD自带的一种特殊的串行队列,放在主队列中得任务,都会放到主线程中执行. 提示:如果把任务放到主队列中进 ...

  6. iOS开发多线程篇—GCD的常见用法

    iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...

  7. java 多线程四

    java 多线程一 java 多线程二 java 多线程三 java 多线程四 一个生产者,消费者的例子: import java.util.Stack; /** * Created by root ...

  8. swift 多线程及GCD

    1.基本概念 1)进程: 进程是指在系统中正在运行的一个应用程序.每个进程之间是独立的,每个进程运行在其专用且受保护的内存空间里.某进程内的线程在其它进程不可见 2)线程: 1个进程要执行任务,必须有 ...

  9. 多线程编程 - GCD(转)

    原文:http://blog.csdn.net/q199109106q/article/details/8566300 一.简介 在iOS所有实现多线程的方案中,GCD应该是最有魅力的,因为GCD本身 ...

  10. 网络与多线程---OC中多线程方法GCD(二)

    小编在前一篇中介绍了多线程实现的五种常用方法.在接下来所介绍的这种方法是最具有魅力的,最具有诱惑的实现多线程的方案---GCD 一.什么是GCD GCD是Grand Central Dispatch的 ...

随机推荐

  1. Cocoa 框架为什么采用两阶段的方式来创建对象?

    对于之前一直使用C#语言的我来说,刚开始接触Objective-c来创建对象时很迷惑,为何创建对象一般情况下需要通过发送两个消息(调用两个方法)才能创建一个类实例对象(例如[[UIButton all ...

  2. Windows 安装 pip管理工具

    Step 1: 设置Python环境变量(我的Python 是 2.7.3) SETX PATH "%path%;D:\python;D:\python\Scripts" 也可以在 ...

  3. 40个容易上瘾的HTML5网页游戏,总有一款适合你

    我记得姐姐家的孩子在刚刚才学会走路,说话还不能完整的时候就已经能自己用小手点出小游戏的网站来一个人自娱自乐.我一直在想这一代跟着计算机一起茁壮成长的孩子会不会也和美国那一代人一样,出现9岁的黑客和计算 ...

  4. jquery的map()和each()方法

    1. map()方法 //找到所有的标题元素,映射它们的ID,并转化为数组后排序 $(':header').map(function(){return this.id}).toArray().sort ...

  5. blazeDS集成spring的remote访问

     欢迎交流转载,请注明出处:http://www.cnblogs.com/shizhongtao/p/3490037.html 上一篇我只是简单实用blazeds创建了一个实例,大多数开发中,都是结合 ...

  6. DTcms会员中心添加新页面-会员投稿,获得所有文章并分页

    DAL.article.cs /// <summary> /// 自定义:获得查询分页数据 /// </summary> public DataSet GetList(int ...

  7. 【转】c#文件操作大全(二)

    61.文件夹移动到整合操作 FolderDialog aa = new FolderDialog();            aa.DisplayDialog();            if (aa ...

  8. 用CSS3写的小案例-图片缩放隐藏内容显示

    思路分析 (1).搭建界面 (2).鼠标移到图片的时候,放大显示 (3).鼠标移入到当前的li标签里面找到后面的div让其显示出来 <!DOCTYPE html> <html lan ...

  9. 使用PHP获取汉字的拼音(全部与首字母)

    <?php /** * 取汉字拼音 * edit by www.jbxue.com */ class GetPingYing { private $pylist = array( 'a'=> ...

  10. SQL优化的四个方面,缓存,表结构,索引,SQL语句

    一,缓存 数据库属于 IO 密集型的应用程序,其主要职责就是数据的管理及存储工作.而我们知道,从内存中读取一个数据库的时间是微秒级别,而从一块普通硬盘上读取一个IO是在毫秒级别,二者相差3个数量级.所 ...