********************************* 基本概念 ***********************************

1. Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法,是苹果主推的多线程处理机制。在多核CPU的状态下,GCD的性能很高。

它自动利用更多的CPU内核,管理线程生命周期,程序员不需要编写任何线程管理代码,只需要给定要让GCD执行的任务。

2. GCD是纯C语言的,GCD中的函数大多数以dispatch开头。

3. GCD存在于 libdispatch.dylib 库中,但不需要手动导入,默认包含。

4. GCD的两个核心概念:任务队列

将任务添加到队列中,GCD会自动将队列中的任务取出,放到对应的线程中执行,遵行FIFO原则:先进先出,后进后出。

5. GCD一般和Block一起使用,在Block回调中处理程序操作。

****************************** GCD的三种调度队列 ******************************

首先需要明确4个术语的概念:

1. 异步(async):在另一条线路中执行,具备开启新线程的能力

2. 同步(sync):在当前线路执行,不具备开启新线程的能力

3. 并行(concurrent):自动开启多个线程让多个任务同时执行,并行功能只在异步条件下才有效

4. 串行(serial):一个任务执行完成才执行下一个

总而言之:同步和异步决定要不要开启新的线程,并行和串行决定任务执行的方式。

GCD的三种调度队列:

1. 运行在主线程的主队列Main queue,一般是执行和UI相关的任务比如更新UI的显示,通过dispatch_get_main_queue获取。

2. 并发队列global dispatch queue,一般是后台长时间执行的任务比如下载,默认提供,不需要创建,通过dispatch_get_global_queue获取。

 dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags)
 // dislatch_queue_t 表示返回的是一个队列
 /* 第一个参数dispatch_queue_priority_t priority表示优先级,后面会使用默认优先级
 DISPATCH_QUEUE_PRIORITY_DEFAULT */
 // 第二个参数unsigned long flags是以后才会使用的,所以先传0

 // 用法
 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
 // 获得全局并发队列queue

3. 串行队列serial queues,获得串行有两种途径

1) 使用dispatch_queue_create函数创建串行队列

 dispatch_queue_t  dispatch_queue_create(const char *label,  dispatch_queue_attr_t attr)
 // 第一个参数是队列名称,第二个参数是队列属性,一般传NULL

 // 用法
 dispatch_queue_t queue = dispatch_queue_create("blahblahblah",  NULL);

 //非ARC需要手动释放队列
 //dispatch_release(queue);

2) 使用主队列(一种特殊的串行队列,GCD自带的在主线程中执行的队列)

 dispatch_get_main_queue()

 // 用法
 dispatch_queue_t queue = dispatch_get_main_queue();

********************************* 代码示例 **********************************

1. 用异步函数向并发队列添加任务

// ViewController.m

#import <ViewController.h>

@interface ViewController()

@end

@implementation ViewController
-(void)viewDidLoad{
    [super viewDidLoad];
    //1. 获得全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,);
    //2. 添加任务到队列中
    dispatch_async(queue,^{
        NSLog(@"下载图片1----%@",[NSThread currentThread]);
    });
    dispatch_async(queue,^{
        NSLog(@"下载图片2----%@",[NSThread currentThread]);
    });
    dispatch_async(queue,^{
        NSLog(@"下载图片3----%@",[NSThread currentThread]);
    });
    NSLog(@"主线程----%@",[NSThread mainThread]);

}
@end

// 异步,并发,开启了3个子线程

2. 用异步函数向串行队列添加任务

// ViewController.m

#import <ViewController.h>

@interface ViewController()

@end

@implementation ViewController
-(void)viewDidLoad{    [super viewDidLoad];
    NSLog(@"主线程----%@",[NSThread mainThread]);
    dispatch_queue_t queue = diapatch_queue_create("BlahBlahBlah",NULL);
    dispatch_async(queue,^{
        NSLog(@"下载图片1----%@",[NSThread currentThread])
    });
    dispatch_async(queue,^{
        NSLog("下载图片2----%@",[NSThread currentThread]);
    })
    diapatch_async(queue,^{
        NSLog("下载图片3----%@",[NSThread currentThread]);
    })

    // 释放队列
    // dispatch_release(queue);
)

// 异步,串行,只开启一条子线程,子线程的任务串行执行

3. 用同步函数向并发队列添加任务

 // ViewController.m

 #import <ViewController.h>

 @interface ViewController()

 @end

 @implementation ViewController
 -(void)viewDidLoad{
     [super viewDidLoad];
     NSLog(@"主线程----%@",[NSThread mainThread]);
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,);
     dispatch_sync(queue,^{
         NSLog("下载图片1----%@",[NSThread currentThread]);
     })
     dispatch_sync(queue,^{
         NSLog("下载图片2----%@",[NSThread currentThread]);
     })
     dispatch_sync(queue,^{
         NSLog("下载图片3----%@",[NSThread currentThread]);
     })

 )

 //  同步,并发,并发队列失去并发功能,不具备开启新线程的能力,只有主线程

4. 用同步函数向串行队列添加任务

 // ViewController.m

 #import <ViewController.h>

 @interface ViewController()

 @end

 @implementation ViewController
 -(void)viewDidLoad{
     [super viewDidLoad];
     NSLog(@"主线程----%@",[NSThread mainThread]);
     dispatch_queue_t queue = dispatch_queue_create("blahblahblah",NULL);
     dispatch_sync(queue,^{
         NSLog(@"下载图片1----%@",[NSThrea currentThread]);
     })
     dispatch_sync(queue,^{
         NSLog(@"下载图片2----%@",[NSThrea currentThread]);
     })
     dispatch_sync(queue,^{
         NSLog(@"下载图片3----%@",[NSThrea currentThread]);
     })

 )
 @end

 // 同步,串行,没有开启新线程的能力,只有主线程

总结:

同步函数

(1)并发队列:不会开线程

(2)串行队列:不会开线程

异步函数

(1)并发队列:能开启N条线程

(2)串行队列:开启1条线程

********************************线程死锁***********************************

不能使用同步函数向主线程添加任务:

 dispatch_sync(diapatch_get_main_queue(),^{
     NSLog("线程死锁");
 })

在程序中写这样的语句不会有任何输出。

理解关键是:dispatch_sync 函数要到block里的内容执行完才能返回,主线程要等待函数返回。

dispatch_async 函数一被调用,马上返回,因此主线程得到返回就可以去做别的事。

原因在于:主线程调用同步函数dispatch_sync,添加任务到主队列(属于串行队列),主线程等待函数的返回,函数等待主线程结束才能执行block的内容,而同步函数必须等到执行完内部内容才能返回,因此造成线程死锁。

就像:A等待B买回来的材料才知道该干嘛,而B需要A提供自己要做什么的信息来决定买什么材料。

因此要向主队列中添加任务,用异步函数。

 dispatch_async(dispatch_get_main_queue,^{
     NSLog(@"不会造成线程死锁");
 })

****************************持续更新中****************************

多线程-GCD学习笔记的更多相关文章

  1. Java多线程技术学习笔记(二)

    目录: 线程间的通信示例 等待唤醒机制 等待唤醒机制的优化 线程间通信经典问题:多生产者多消费者问题 多生产多消费问题的解决 JDK1.5之后的新加锁方式 多生产多消费问题的新解决办法 sleep和w ...

  2. 多线程编程学习笔记——async和await(一)

    接上文 多线程编程学习笔记——任务并行库(一) 接上文 多线程编程学习笔记——任务并行库(二) 接上文 多线程编程学习笔记——任务并行库(三) 接上文 多线程编程学习笔记——任务并行库(四) 通过前面 ...

  3. 多线程编程学习笔记——async和await(二)

    接上文 多线程编程学习笔记——async和await(一) 三.   对连续的异步任务使用await操作符 本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步 ...

  4. 多线程编程学习笔记——async和await(三)

    接上文 多线程编程学习笔记——async和await(一) 接上文 多线程编程学习笔记——async和await(二) 五.   处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...

  5. 多线程编程学习笔记——使用异步IO(一)

    接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...

  6. 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端

    接上文 多线程编程学习笔记——使用异步IO 二.   编写一个异步的HTTP服务器和客户端 本节展示了如何编写一个简单的异步HTTP服务器. 1.程序代码如下. using System; using ...

  7. 多线程编程学习笔记——异步调用WCF服务

    接上文 多线程编程学习笔记——使用异步IO 接上文 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端 接上文 多线程编程学习笔记——异步操作数据库 本示例描述了如何创建一个WCF服务,并宿主 ...

  8. 多线程编程学习笔记——使用异步IO

    接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...

  9. Java多线程技术学习笔记(一)

    目录: 概述 多线程的好处与弊端 JVM中的多线程解析 多线程的创建方式之一:继承Thread类 线程的状态 多线程创建的方式之二:实现Runnable接口 使用方式二创建多线程的好处 多线程示例 线 ...

随机推荐

  1. div 水平居中

    对需要水平居中的DIV层添加以下属性: margin-left: auto; margin-right: auto;

  2. 【Android XMPP】 学习资料收集贴(持续更新)

    系列一: 基于xmpp openfire smack开发之openfire介绍和部署[1] 基于xmpp openfire smack开发之smack类库介绍和使用[2] 基于xmpp openfir ...

  3. linux route命令学习

    route命令用于显示和操作IP路由表. 没有增加路由之前,route命令的结果如下, sh-# route Kernel IP routing table Destination     Gatew ...

  4. 【转】学习Flex ActionScript 3.0 强烈推荐电子书

    学习Flex ActionScript 3.0 强烈推荐电子书 AdvancED ActionScript 3.0 Animation(<Make things  move>姐妹篇,强烈推 ...

  5. GetTickCount() 函数的作用和用法

    今天项目中60秒倒计时模块需要用到GetTickCount(),这个函数,在此做下整理和总结. 1.定义 For Release configurations, this function retur ...

  6. java 数组注意点

    int[] array1 = new int[4]; int[] array2 = new int[6]; int[] array3 = new int[8]; array2 = array1; ar ...

  7. jquery.validate.js默认配置,jquery.validate.js自定义提示信息

    jquery.validate.js默认配置,jquery.validate.js自定义提示信息 配置jQuery.validator默认的处理方法 >>>>>>& ...

  8. C#发送邮件-C#教程

    如何利用C#实现邮件发送功能?闲话不多说请看代码: public static void SendMail(MyEmail email){//发送验证邮箱邮件.//1.创建邮件MailMessage ...

  9. Linux中Curl命令couldn't connect to host解决方案 php操作Curl(http,https)无法获取远程数据解决方案

    本人在做百度账户第三方登录接口,获取百度token,利用php操作curl post方式发送请求token,出现couldn't connect to host错误.经过调试测试,最后终于成功.回头写 ...

  10. mysql免安装版使用

    打开命令行,到bin目录下,输入net start mysql 启动服务,输入mysql -u root -p回车后输入密码,进入mysql.