学习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. Swift中的注释以及表达式

    Swift程序有两类注释:单行注释(//)和多行注释(/*...*/).注释方法与C.C++和Objective-C语言都是类似的,下面详细介绍一下.1. 单行注释单行注释可以注释整行或者一行中的一部 ...

  2. js 获取 当前时间 时间差 时间戳 倒计时

    开发web一段时间后发现经常使用时间进行一些操作,比较多的就是获取当前时间.对时间进行比较.时间倒计时.时间戳这些部分,每次去用经常忘总是需要去查询,还是自己总结一下比较靠谱. 获取时间戳的方法: 第 ...

  3. C#学习笔记之线程 - 通知Signal

    通知事件等待句柄 Signal With EventWaitHandle 事件等待句柄常用于通知.当一个线程等待直到接收到另外一个线程发出的信号.事件等待句柄是最简单的信号结构,它与C#事件无关.有三 ...

  4. .NET架构师技能体系

    .NET架构师应该掌握什么样的技术?其实这个问题很简单,去看看招聘.NET架构师的公司的职位要求就知道了.比如:http://www.cnblogs.com/guwei4037/p/5615471.h ...

  5. TCP三次握手原理与SYN攻击

    本文内容包括以下几点 1.TCP三次握手四次挥手解析 2.迭代型服务器程序编写,并给出客户端,结合这一模式详细介绍Berkeley套接字的使用 3.介绍SYN攻击的原理 TCP连接建立,传输数据,连接 ...

  6. sublime text2 中文乱码的解决办法

    1.安装Sublime Package Control 在Sublime Text 2上用Ctrl+-打开控制台并在里面输入以下代码,Sublime Text 2就会自动安装Package Contr ...

  7. Win32的绘图消息大集合

    AbortPath 抛弃选入指定设备场景中的所有路径.也取消目前正在进行的任何路径的创建工作AngleArc 用一个连接弧画一条线Arc 画一个圆弧BeginPath 启动一个路径分支CancelDC ...

  8. 退出telnet

    telnet时,很多时候通过ctrl+c依然无法退出.可以采取下面的方式进行退出:  ctrl+],然后进入 telnet>,然后输入q或quit即可.

  9. 查看某一个点是否在某个多边形内 使用ST_Contains函数

    查看某一个点是否在某个多边形内  使用ST_Contains函数 --LINESTRING ( 121.312350 30.971457 , 121.156783 31.092221 , 121.35 ...

  10. 【 Quartz】使用 JobListener (任务监听器可实现) 我想在一个任务执行后在执行第二个任务怎么办呢

    http://liuzidong.iteye.com/blog/1147528 Quartz之JobExecutionException 博客分类: Java Quartz quartzjobexec ...