学习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. 值类型与引用类型(特殊的string) Typeof和GetType() 静态和非静态使用 参数传递 相关知识

    学习大神博客链接: http://www.cnblogs.com/zhili/category/421637.html 一 值类型与引用类型 需要注意的string 是特殊类型的引用类型. 使用方法: ...

  2. Eclipse Class Decompiler---Java反编译插件

    若转载,请标明出处http://www.cnblogs.com/last_hunter/p/5626779.html,谢谢! ------------------------------------- ...

  3. [GeekBand] STL与泛型编程(2)

    本篇文章在上一篇文章的基础上进一步介绍一些常用的容器以及STL的一些深入知识. 一. Stack和Queue 栈和队列是非常常用的两种数据结构,由deque适配而来.关于数据结构的知识这里就不在介绍了 ...

  4. windbg基本命令

    1, .reload k 当前调用堆栈.u 当前正在执行的代码. 2, ~ 查看被调试进程中的线程信息每一行是一个线程的信息.第一行中,0 表示这个进程的编号:1ff4.1038 是 16 进制数字, ...

  5. C/C++输入输出总结

    *string类:  1.cin>>string时,遇到'\n'或者空格即停止,并且'\n'或空格仍留在输入里,即只读了一个单词或什么都没读,但string类自己处理好了空字符什么的.下一 ...

  6. 视酷即时通讯系统应用源码 V1.0

    视酷即时通讯系统(原创),成熟稳定,拥有和微信一样强大的功能不再是梦,节省几个月研发时间迅速融合进项目中: 1.首家支持聊天室群聊 2.支持和微信一样的语音聊天,可以显示时长.未读状态,自动轮播未读语 ...

  7. 隐藏内容_网络推广_seo中级视频教程详解

    课程背景:SEO(Search Engine Optimization),汉译为搜索引擎优化.搜索引擎优化是一种利用搜索引擎的搜索规则来提高目的网站在有关搜索引擎内的排名的方式.SEO目的理解是:为网 ...

  8. RHEL6.3 ftp服务器参数的戏说——不看白不看,看了不白看

    大家都知道ftp服务器的应用何止广,简直就是无处不在,配置简单的ftp服务谁都会,无外乎就是刚安装好ftp服务,一启动就ok了:或是达到简单的上传下载修改下/var/ftp/pub的权限,配合配置文件 ...

  9. javascript之高级函数应用思想

    1.级联函数:应用对象方法调用的连写 function A(){ this.a = ''; this.b = ''; this.c = ''; } //改造一下 A.prototype = { A.p ...

  10. [译]Java Thread wait, notify和notifyAll示例

    Java Thread wait, notify和notifyAll示例 Java上的Object类定义了三个final方法用于不同线程间关于某资源上的锁状态交互,这三个方法是:wait(), not ...