iOS中多线程知识总结(二)
1.GCD
GCD全称是Grand Central Dispatch,译为"强大的中枢管理器"
1)什么是任务?什么是队列?
任务和队列是GCD的核心.
任务: 执行什么操作
队列: 用来存放任务
2)用GCD创建线程的两种方式.
01.使用并发队列创建
//01 获得并发队列
/*
第一个参数:C语言的字符串 对队列的名称(com.520it.www.DownloadQueue)
第二个参数:队列的类型
DISPATCH_QUEUE_SERIAL 串行队列
DISPATCH_QUEUE_CONCURRENT 并发队列
*/
dispatch_queue_t queue = dispatch_queue_create("www.baidu.com", DISPATCH_QUEUE_CONCURRENT); //02 封装任务并把任务添加到队列
dispatch_async(queue, ^{
NSLog(@"download1---%@",[NSThread currentThread]);
});
02.使用全局队列创建
//02 使用获得全局并发队列,开启子线程 /*
第一个参数:队列的优先级
第二个参数:
*/
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
//02 封装任务并把任务添加到队列
dispatch_async(queue, ^{
NSLog(@"download1---%@",[NSThread currentThread]);
});
3)同步,异步,并发,串行
同步函数: 在当前线程中执行任务,不具备开线程的能力
异步函数: 在新的线程中执行任务,具备开线程的能力
并发队列: 多个任务并发执行
串行队列: 一个任务执行完之后,再执行下一个
4)是否会开启线程
01 异步函数+并发队列:开启多条线程,并发执行任务
02 异步函数+串行队列:开启一条线程,串行执行任务
03 同步函数+并发队列:不开线程,串行执行任务
04 同步函数+串行队列:不开线程,串行执行任务
05 异步函数+主队列:不开线程,在主线程中串行执行任务
06 同步函数+主队列:不开线程,串行执行任务(注意死锁发生)
5) 为什么使用同步函数+主队列(串行队列)会发生死锁?
首先要明白主队列是在主线程中,而同步函数不具备开启子线程的能力.假设A正在主线程中执行,而在A执行的过程中又需要去执行B.由于同步函数+主队列并不会开启子线程,只能去主线程中执行,而主线程中A正在执行.由A需要C去执行,C又需要等A执行完毕,才能执行,就会造成死锁.
6) GCD中常用的函数
1)一次性代码,整个程序运行过程中只执行一次,可以用作创建单例,线程安全
static dispatch_once_t onceToken; //内部的实现原理:最开始的时候onceToken==0 如果onceToken==0 那么就执行一次,onceToken=-1
NSLog(@"%zd",onceToken);
dispatch_once(&onceToken, ^{
NSLog(@"once");
});
2)延迟函数
dispatch_queue_t queue = dispatch_queue_create("TestQueue", DISPATCH_QUEUE_SERIAL);
/*
延迟2秒,然后再把任务提交到队列
*/
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), queue, ^{ NSLog(@"GCD----%@",[NSThread currentThread]);
});
3)遍历函数
//快速迭代(并发队列):会开启子线程和主线程一起执行任务,所有的任务并发执行
/*
第一个参数:要遍历的次数
第二个参数:队列 ~ 线程 全局并发队列 == 自己创建的并发队列
自己创建的串行队列 == for循环
主队列:死锁
*/
dispatch_queue_t queue = dispatch_queue_create("TestQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(, queue, ^(size_t i) {
NSLog(@"%zd---%@",i,[NSThread currentThread]);
});
4)栅栏函数
//需求:1)有四个任务,开子线程并发的执行这四个任务
//2)添加任务+++++++,但是要求必须要等1|2都执行完才执行++++,必须要等+++打印执行完才能执行后面的任务
//3)所有的任务都在子线程中执行(dispatch_barrier_async)
//栅栏 = 篱笆
//01 获得并发队列
dispatch_queue_t queue = dispatch_queue_create("TestQueue", DISPATCH_QUEUE_CONCURRENT);
//注意:!!!! 栅栏函数在使用中不能使用全局并发队列(会丧失拦截的功能)
//dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //02 异步函数
dispatch_async(queue, ^{
NSLog(@"1----%@",[NSThread currentThread]);
}); dispatch_async(queue, ^{
NSLog(@"2----%@",[NSThread currentThread]);
}); //特点:拦截上面的任务必须等前面的任务执行完才执行当前的block,必须等当前的block快执行完才执行后面
//dispatch_barrier_async 子线程中执行
//dispatch_barrier_sync 当前线程
dispatch_barrier_async(queue, ^{
NSLog(@"+++++%@",[NSThread currentThread]);
}); dispatch_async(queue, ^{
NSLog(@"3----%@",[NSThread currentThread]);
}); dispatch_async(queue, ^{
NSLog(@"4----%@",[NSThread currentThread]);
});
4:NSOperation(操作队列)
1)基本概念
NSOperation本身是抽象类,只能使用它的子.分别是NSBlockOperation、NSInvocationOperation以及自定义继承自NSOperation的类
2)操作队列的核心是: 队列 + 操作
其实它的使用也很简单,就是先创建队列,然后把你封装的操作加到队列,操作队列默认的是并发队列
3)NSInvocationOperation的使用(使用不多)
//01 创建队列
/*
操作队列:
① 自己创建(自定义)[并发队列*串行队列,默认是并发队列] [[NSOperationQueue alloc]init]
② 主队列[串行队列] [NSOperationQueue MainQueue]
*/
NSOperationQueue *queue = [[NSOperationQueue alloc]init]; //02 封装操作
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download) object:nil]; NSInvocationOperation *op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download) object:nil]; //03 把操作添加到队列
[queue addOperation:op1];
[queue addOperation:op2];
4)NSBlockOperation
1)怎么创建
//01 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init]; //02 封装操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1----%@",[NSThread currentThread]);
}]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2----%@",[NSThread currentThread]);
}]; //03 把操作添加到队列
[queue addOperation:op1]; //addOperation 内部调用start方法
[queue addOperation:op2];
2) 设置依赖和监听(通常在下载的时候用的到)
//01 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSOperationQueue *queue2 = [[NSOperationQueue alloc]init]; //02 封装操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1----%@",[NSThread currentThread]);
}]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2----%@",[NSThread currentThread]);
}]; NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"3----%@",[NSThread currentThread]);
}]; NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"4-下载电影-%@",[NSThread currentThread]);
}]; NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"+++++++5+%@+++",[NSThread currentThread]);
}]; //设置监听 |当op4任务结束的时候会执行block中的代码
//completionBlock 在子线程中执行
op4.completionBlock = ^{
NSLog(@"我已经被下载完了,快点来看我吧--%@",[NSThread currentThread]);
}; //设置依赖
//5-4-3-2-1
[op1 addDependency:op2]; //必须要等任务2执行完毕才能执行任务1
//[op2 addDependency:op1]; !!! 不能设置循环以来 [op2 addDependency:op3];
[op3 addDependency:op4];
[op4 addDependency:op5]; //03 把操作添加到队列
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
[queue addOperation:op4];
[queue2 addOperation:op5];
输出结果:
5)设置最大并发数
/.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init]; //2.设置最大并发数
//注意点:该属性需要在任务添加到队列中之前进行设置
//该属性控制队列是串行执行还是并发执行
//如果最大并发数等于1,那么该队列是串行的,如果大于1那么是并行的
//系统的最大并发数有个默认的值,为-1,如果该属性设置为0,那么不会执行任何任务
queue.maxConcurrentOperationCount = ;
6)暂停和恢复以及取消
//设置暂停和恢复
//suspended设置为YES表示暂停,suspended设置为NO表示恢复
//暂停表示不继续执行队列中的下一个任务,暂停操作是可以恢复的
if (self.queue.isSuspended) {
self.queue.suspended = NO;
}else
{
self.queue.suspended = YES;
} //取消队列里面的所有操作
//取消之后,当前正在执行的操作的下一个操作将不再执行,而且永远都不在执行,就像后面的所有任务都从队列里面移除了一样
//取消操作是不可以恢复的
[self.queue cancelAllOperations];
最后关于GCD 和 NSOperation的对比
)GCD是纯C语言的API,而操作队列则是Object-C的对象。
)在GCD中,任务用块(block)来表示,而块是个轻量级的数据结构;相反操作队列中的『操作』NSOperation则是个更加重量级的Object-C对象。
)具体该使用GCD还是使用NSOperation需要看具体的情况 NSOperation和NSOperationQueue相对GCD的好处有:
)NSOperationQueue可以方便的调用cancel方法来取消某个操作,而GCD中的任务是无法被取消的(安排好任务之后就不管了)。
)NSOperation可以方便的指定操作间的依赖关系。
)NSOperation可以通过KVO提供对NSOperation对象的精细控制(如监听当前操作是否被取消或是否已经完成等)
)NSOperation可以方便的指定操作优先级。操作优先级表示此操作与队列中其它操作之间的优先关系,优先级高的操作先执行,优先级低的后执行。
)通过自定义NSOperation的子类可以实现操作重用,
附:
最近拜读了文顶顶大牛的博客,确实牛,强烈推荐......
iOS中多线程知识总结(二)的更多相关文章
- iOS中多线程知识总结(一)
这一段开发中一直在处理iOS多线程的问题,但是感觉知识太散了,所以就把iOS中多线程的知识点总结了一下. 1.基本概念 1)什么是进程?进程的特性是什么? 进程是指在系统中正在运行的一个应用程序. ...
- iOS中多线程原理与runloop介绍
一.线程概述 有些程序是一条直线,起点到终点:有些程序是一个圆,不断循环,直到将它切断.直线的如简单的Hello World,运行打印完,它的生命周期便结束了,像昙花一现那样:圆如操作系统,一直运行直 ...
- iOS 中多线程的简单使用
iOS中常用的多线程操作有( NSThread, NSOperation GCD ) 为了能更直观的展现多线程操作在SB中做如下的界面布局: 当点击下载的时候从网络上下载图片: - (void)loa ...
- 在iOS中使用ZBar扫描二维码
最近在做的项目中需要用到二维码扫描功能,之前在Android中使用过ZXing识别二维码,ZXing也有对应的iOS版本,经过了解,ZBar也是一个常用的二维码识别软件,并分别提供了iOS和Andro ...
- Quartz 2D在ios中的使用简述二:创建画布
在iOS中使用Quartz画图时,第一步就是要获取画布(图形上下文),然后再画布上做各种操作.先看下CoreGraphics.h这个头文件,就可以知道能够创建多少种上下文类型. #include &l ...
- IOS中多线程的总结
首先要知道线程和进程的区别.一个系统上运行的每一个应用程序都是一个线程.而进程中要执行的任务都是在线程上来实现的,所以说线程是进程的最小执行单元. 进程最少要有一个线程.多线程,顾名思义就是多条线程. ...
- DELPHI中多线程知识【转】
本文的内容取自网络,并重新加以整理,在此留存仅仅是方便自己学习和查阅.所有代码均亲自测试 delphi7下测试有效.图片均为自己制作. 多线程应该是编程工作者的基础技能, 但这个基础我从来没学过,所以 ...
- 网络与多线程---OC中多线程方法GCD(二)
小编在前一篇中介绍了多线程实现的五种常用方法.在接下来所介绍的这种方法是最具有魅力的,最具有诱惑的实现多线程的方案---GCD 一.什么是GCD GCD是Grand Central Dispatch的 ...
- iOS中多线程的实现方案
什么是主线程? 一个iOS程序运行后,默认会开启一条线程,称为“主线程”或“UI线程” 主线程的主要作用 1.显示/刷新UI界面 2.处理UI事件(比如点击事件,滚动事件,拖拽事件) 主线程的使用注意 ...
随机推荐
- NHibernate开发入门
首先,我们了解一下ORM是什么?ORM指对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程 ...
- A*算法的原理 <转>
第一部分:A*算法简介 写这篇文章的初衷是应一个网友的要求,当然我也发现现在有关人工智能的中文站点实在太少,我在这里 抛砖引玉,希望大家都来热心的参与. 还是说正题,我先拿A*算法开刀, ...
- 关闭rdlc报表打印预览后,关闭客户端,抛出异常“发生了应用程序级的异常 将退出”
问题:关闭rdlc报表打印预览后,关闭客户端,抛出异常“发生了应用程序级的异常 将退出” 办法:在容纳ReportViewer的窗体后台代码中,添加如下代码即可 protected override ...
- 苹果手机微信上form表单提交的问题
场景:前端页面请求后端php,返回带form表单dom元素,然后将其追在页面上,返回的html字段中包含表单自动提交的代码,想法是将带有表单自动提交的dom元素追加到页面上,然后表单自动提交到另外一个 ...
- echo.js 延迟加载图片控件
echo.js的github地址:https://github.com/toddmotto/echo echo是一个独立的JavaScript.轻量级的.延迟图片加载插件,echo压缩后体积不到1 ...
- C#在Linux+Mono环境中使用微信支付证书
最近特殊的需求,要把微信平台一个功能页面部署到Linux(CentOS6.5)下,其中涉及到微信支付退款. 鉴于之前实践过mono+jexus+asp.net mvc的部署,于是问题重点在于解决对商户 ...
- C到C++的升级
const 在C中只是个“只读变量”,并不是真正意义上的常量,通过指针能改变它,如下 #include<stdio.h> int main() { ;//声明只读变量a为0 int* p= ...
- Go 语言的基本数据类型
Go 语言的基本数据类型 0)变量声明 var 变量名字 类型 = 表达式 例: 其中“类型”或“= 表达式”两个部分可以省略其中的一个. 1)根据初始化表达式来推导类型信息 2)默认值初始化为0. ...
- Java序列化、反序列化和单例模式
学习JAVA的时候,特别是涉及到网络编程时,我们时常让我们的实体类实现一个接口 public class Entity implements Serializable{ } 这样子我们可以通过输入输出 ...
- php清理当前目录下的指定文件和空目录(源码),建议服务器端执行
<?php /** * @desc 解析当前目录并递归删除目录下的指定文件 * @author mengdj<mengdj@outlook.com> 2014.10.02 1530 ...