2.多线程-GCD
1.基本概念
/**
串行队列 */
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//串行队列,同步方法
[self serailSync]; //串行队列,异步方法
// [self serailAsync];
} /**
串行队列,异步方法 1.打印顺序 : 从上到下依次执行,它是串行队列 2.在哪条线程上执行:在子线程,因为它是异步执行,异步,就是不在当前线程里面执行 应用场景:耗时间,有顺序的任务 1.登录--->2.付费--->3.才能看 */
- (void)serailAsync{
//1.创建一个串行队列
/**
参数1:队列的标识fuhao,一般是公司的域名倒写
www.itheima.com
参数2:队列的类型 DISPATCH_QUEUE_SERIAL 串行队列
DISPATCH_QUEUE_CONCURRENT 并发队列
*/
dispatch_queue_t serialQueue = dispatch_queue_create("com.itheima.queue1", DISPATCH_QUEUE_SERIAL); //2.创建三个任务
void (^task1) () = ^(){
NSLog(@"task1---%@",[NSThread currentThread]);
}; void (^task2) () = ^(){
NSLog(@"task2---%@",[NSThread currentThread]);
}; void (^task3) () = ^(){
NSLog(@"task3---%@",[NSThread currentThread]);
}; //3.把我们上面创建好的三个任务,添加到队列中去,这个队列就会自己开始调用我们的任务
//异步方法执行
dispatch_async(serialQueue, task1);
dispatch_async(serialQueue, task2);
dispatch_async(serialQueue, task3);
} /**
串行队列,同步方法 1.打印顺序 : 从上到下,依次打印,因为串行的 2.在哪条线程上执行:主线程,因为是同步方法,所以在当前线程里面执行,恰好当前线程是主线程,所以它就在主线程上面执行 应用场景:开发中很少用 */ - (void)serailSync{
//1.创建一个串行队列
/**
参数1:队列的标识fuhao,一般是公司的域名倒写
www.itheima.com
参数2:队列的类型 DISPATCH_QUEUE_SERIAL 串行队列
DISPATCH_QUEUE_CONCURRENT 并发队列
*/
dispatch_queue_t serialQueue = dispatch_queue_create("com.itheima.queue1", DISPATCH_QUEUE_SERIAL); //2.创建三个任务
void (^task1) () = ^(){
NSLog(@"task1---%@",[NSThread currentThread]);
}; void (^task2) () = ^(){
NSLog(@"task2---%@",[NSThread currentThread]);
}; void (^task3) () = ^(){
NSLog(@"task3---%@",[NSThread currentThread]);
}; //3.把我们上面创建好的三个任务,添加到队列中去,这个队列就会自己开始调用我们的任务
//同步方法执行
dispatch_sync(serialQueue, task1);
dispatch_sync(serialQueue, task2);
dispatch_sync(serialQueue, task3);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//1.并发队列,同步任务
//[self concurrentSync];
//2.并发队列,异步任务
[self concurrentAsync];
}
- (void)concurrentAsync{
/**
并发队列,异步方法
1.打印顺序 :无序的
2.在哪条线程上执行:在子线程上执行,第一个任务,都在它自己的线程上执行
开N条,它是由底层可调度线程池来决定的,可调度线程池它是有一个重用机制
应用场景:
半月转
开头 中间 结尾
下载电视剧某一集的时候,可以把我们的片头,片尾,中间内容 一起下
最后,拼接组合一下,就可以播放了
片头,中间内容,片尾
*/
//1.创建一个并发的队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.itheima.queue2", DISPATCH_QUEUE_CONCURRENT);
//2.创建三个任务
void (^task1) () = ^(){
NSLog(@"task1---%@",[NSThread currentThread]);
};
void (^task2) () = ^(){
NSLog(@"task2---%@",[NSThread currentThread]);
};
void (^task3) () = ^(){
NSLog(@"task3---%@",[NSThread currentThread]);
};
//3.将我们的三个任务,添加到队列中
//异步方法去执行
dispatch_async(concurrentQueue, task1);
dispatch_async(concurrentQueue, task2);
dispatch_async(concurrentQueue, task3);
}
/**
并发队列,同步方法
1.打印顺序 : 依次执行,因为它是同步的
2.在哪条线程上执行:主线程,因为它是同步方法,它就在当前线程里面执行,主线程,依次执行
当它遇到同步的时候,并发队列,还是依次执行
所以说,方法的优先级会比队列的优先级高
* 只要是同步方法,都只会在当前线程里面执行,不会开子线程
应用场景:
开发中几乎不用
*/
- (void)concurrentSync{
//1.创建一个并发的队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.itheima.queue2", DISPATCH_QUEUE_CONCURRENT);
//2.创建三个任务
void (^task1) () = ^(){
NSLog(@"task1---%@",[NSThread currentThread]);
};
void (^task2) () = ^(){
NSLog(@"task2---%@",[NSThread currentThread]);
};
void (^task3) () = ^(){
NSLog(@"task3---%@",[NSThread currentThread]);
};
//3.将我们的三个任务,添加到队列中
//同步方法去执行
dispatch_sync(concurrentQueue, task1);
dispatch_sync(concurrentQueue, task2);
dispatch_sync(concurrentQueue, task3);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//1.主队列,异步
[self mainAsync];
//2.主队列,同步
//[self mainSync];
}
/**
主队列,同步任务有问题,不能用
`主队列`只有在`主线程空闲`的时候,才会去调度它里面的任务去执行
*/
- (void)mainSync{
//只是用来调试,说明我们来到了这个方法
NSLog(@"%s",__func__);
//1.获取主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
//2.搞三个任务
void (^task1) () = ^(){
NSLog(@"task1===%@",[NSThread currentThread]);
};
void (^task2) () = ^(){
NSLog(@"task2===%@",[NSThread currentThread]);
};
void (^task3) () = ^(){
NSLog(@"task3===%@",[NSThread currentThread]);
};
//3.将任务添加到主队列中
dispatch_sync(mainQueue, task1);
dispatch_sync(mainQueue, task2);
dispatch_sync(mainQueue, task3);
NSLog(@"mainSync----end");
}
/**
主队列,异步任务
1.执行顺序:依次执行,因为它在主线程里面执行
* 似乎与我们的异步任务有所冲突,但是因为它是主队列,所以,只在主线程里面执行
2.是否会开线程:不会开,因为它在主线程里面执行
应用场景:
当做了耗时间操作之后,当我们需要回到主线程更新UI的时候,就非它不可
*/
- (void)mainAsync{
//1.获取主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
//2.搞三个任务
void (^task1) () = ^(){
NSLog(@"task1===%@",[NSThread currentThread]);
};
void (^task2) () = ^(){
NSLog(@"task2===%@",[NSThread currentThread]);
};
void (^task3) () = ^(){
NSLog(@"task3===%@",[NSThread currentThread]);
};
//3.将任务添加到主队列中
dispatch_async(mainQueue, task1);
dispatch_async(mainQueue, task2);
dispatch_async(mainQueue, task3);
NSLog(@"---mainAsync---end");
}
2.常用代码
/**
如果要在子线程中执行 除了`主队列`都可以,串行,并发,全局都可以 去主线程只有一个方法,那就是主队列,异步
*/
dispatch_async(dispatch_get_global_queue(, ), ^{
//1.去子线程里面加载图片 NSLog(@"假装在下载...%@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:3.0]; //2.去主线程更新UI
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%@----更新UI",[NSThread currentThread]);
});
});
3.同步的作用
/**
同步的作用:保证我们任务执行的先后顺序 1.登录 2.同时下载三部小电影
*/
- (void)execLongTimeOperation{
dispatch_async(dispatch_get_global_queue(, ), ^{
//1.登录,同步在当前线程里面工作
dispatch_sync(dispatch_get_global_queue(, ), ^{
NSLog(@"%@----登录...",[NSThread currentThread]); [NSThread sleepForTimeInterval:3.0];
}); //2.同时下载三部小电影(不需要先后顺序)
dispatch_async(dispatch_get_global_queue(, ), ^{
NSLog(@"downLoadA----%@",[NSThread currentThread]);
}); dispatch_async(dispatch_get_global_queue(, ), ^{
NSLog(@"downLoadV----%@",[NSThread currentThread]);
}); dispatch_async(dispatch_get_global_queue(, ), ^{
NSLog(@"downLoadI----%@",[NSThread currentThread]);
});
});
}
4.延迟操作
/**
参数1.延时多少纳秒,整个延迟3秒
参数2:是决定,参加在哪个线程里面调用
参数3:任务执行的代码块 dispatch_after 异步的 应用场景:
动画 */
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)( * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"---下载完毕---%@",[NSThread currentThread]);
}); NSLog(@"---end---");
5.单例
+ (instancetype)sharedNetWorkToos;
static id _instance;
+ (instancetype)sharedNetWorkToos{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
}); return _instance;
} + (instancetype)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
}); return _instance;
} - (id)copyWithZone:(NSZone *)zone{
return _instance;
}
6.调度组,组内的线程全部执行完,会到dispatch_group_notify定义的方法中
//1.创建一个调度组
dispatch_group_t group = dispatch_group_create(); //2.获取全局队列
dispatch_queue_t globalQueue = dispatch_get_global_queue(, ); //3.三个下载任务
void (^task1) () = ^(){
NSLog(@"%@----下载片头",[NSThread currentThread]);
}; void (^task2) () = ^(){
NSLog(@"%@----下载中间的内容",[NSThread currentThread]); [NSThread sleepForTimeInterval:5.0]; NSLog(@"--下载中间内容完毕---");
}; void (^task3) () = ^(){
NSLog(@"%@----下载片尾",[NSThread currentThread]);
}; //3.需要将我们的队列和任务,加入组内去监控
dispatch_group_async(group, globalQueue, task1);
dispatch_group_async(group, globalQueue, task2);
dispatch_group_async(group, globalQueue, task3); //4.监听的函数
/**
参数1:组
参数2:参数3在哪个线程里面执行
参数3:组内完全下载完毕之后,需要执行的代码
*/
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//表示组内的所有任务都完成之后,会来到这里 NSLog(@"把下好的视频按照顺序拼接好,然后显示在UI去播放");
});
调度组的实现原理
/**
应用场景
比如我去同时开三个线程下载视频,只有当三个视频完全下载完毕之后,我才能做后续的事,
这个就需要用到调度组,这个调度组,就能监听它里面的任务是否都执行完毕
*/
- (void)execGroupDispatch{
//1.创建一个调度组
dispatch_group_t group = dispatch_group_create(); //2.获取全局队列
dispatch_queue_t globalQueue = dispatch_get_global_queue(, ); //3.三个下载任务 dispatch_group_enter(group); //引用计数+1
void (^task1) () = ^(){
NSLog(@"%@----下载片头",[NSThread currentThread]); dispatch_group_leave(group); //引用计数-1
}; dispatch_group_enter(group); //引用计数+1
void (^task2) () = ^(){
NSLog(@"%@----下载中间的内容",[NSThread currentThread]); [NSThread sleepForTimeInterval:5.0]; NSLog(@"--下载中间内容完毕---");
dispatch_group_leave(group);//引用计数-1
}; void (^task3) () = ^(){
NSLog(@"%@----下载片尾",[NSThread currentThread]);
}; //3.需要将我们的队列和任务,加入组内去监控
dispatch_group_async(group, globalQueue, task1);
dispatch_group_async(group, globalQueue, task2);
dispatch_group_async(group, globalQueue, task3); //4.监听的函数
/**
参数1:组
参数2:参数3在哪个线程里面执行
参数3:组内完全下载完毕之后,需要执行的代码
*/
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//表示组内的所有任务都完成之后,会来到这里 NSLog(@"把下好的视频按照顺序拼接好,然后显示在UI去播放");
});
}
7.定时器与运行循环
@interface ViewController ()
@property (nonatomic, assign) int count;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self performSelectorInBackground:@selector(subThreadRun) withObject:nil];
}
- (void)subThreadRun{
NSLog(@"%s----%@",__func__,[NSThread currentThread]);
//1.定义了一个定时器
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timeEvent) userInfo:nil repeats:YES];
//2.将我们的定时器加入到运行循环,只有加入到当前的运行循环里面去,他才知道你这个时候,有一个定时任务
/**
NSDefaultRunLoopMode 当拖动的时候,它会停掉
因为这种模式是互斥的
forMode:UITrackingRunLoopMode 只有输入的时候,它才会去执行定时器任务
NSRunLoopCommonModes 包含了前面两种
*/
//[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
//[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
//下载,定时源事件,输入源事件,如果放在子线程里面,如果想要它执行任务,就必须开启子线程的运行循环
CFRunLoopRun();
}
- (void)timeEvent{
self.count ++;
NSLog(@"%d",self.count);
if (self.count==) {
NSLog(@"---guale---");
//停止当前的运行循环
CFRunLoopStop(CFRunLoopGetCurrent());
}
}
2.多线程-GCD的更多相关文章
- iOS 多线程GCD的基本使用
<iOS多线程简介>中提到:GCD中有2个核心概念:1.任务(执行什么操作)2.队列(用来存放任务) 那么多线程GCD的基本使用有哪些呢? 可以分以下多种情况: 1.异步函数 + 并发队列 ...
- iOS多线程 GCD
iOS多线程 GCD Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法. dispatch queue分成以下三种: 1)运行在主线程的Main que ...
- 修改版: 小伙,多线程(GCD)看我就够了,骗你没好处!
多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能.具有这种能力的系 ...
- ios多线程-GCD基本用法
ios中多线程有三种,NSTread, NSOperation,GCD 这篇就讲讲GCD的基本用法 平时比较多使用和看到的是: dispatch_async(dispatch_get_global_q ...
- iOS 多线程GCD简介
一.简介 1.1 GCD (Grand Central Dispatch )是Apple开发的一个多核编程的解决方法. Grand 含义是“伟大的.宏大的”,Central含义“中央的”,Dispat ...
- 多线程GCD的基本使用以及注意点
GCD的使用 一:队列 1.串行队列:添加到队列中的任务是一个一个执行的 2.并行(发)队列:添加到队列中的任务是多个同时执行的(一个队列中的多个任务可以同时执行) 3.主队列:里 ...
- IOS开发之多线程 -- GCD的方方面面
前言:这篇GCD的博文是本人阅读了很多海内外大神的关于GCD的文章,以及结合之前自己对GCD的粗浅的认识,然后取其精华,去其槽粕,综合起来的笔记,而且是尽可能的以通熟易懂的并且是正确的理论论述方式呈现 ...
- 刀哥多线程GCD核心概念gcd
GCD GCD 核心概念 将任务添加到队列,并且指定执行任务的函数 任务使用 block 封装 任务的 block 没有参数也没有返回值 执行任务的函数 异步 dispatch_async 不用等待当 ...
- ios开发多线程--GCD
引言 虽然GCD使用很广,而且在面试时也经常问与GCD相关的问题,但是我相信深入理解关于GCD知识的人肯定不多,大部分都是人云亦云,只是使用过GCD完成一些很简单的功能.当然,使用GCD完成一些简单的 ...
- 多线程GCD
经常使用:规避很多线程相关的复杂的逻辑 为什么会gcd?因为pthread和nsthread要求开发人员对线程相关的知识了解深入; 手动启动线程:加锁/解锁;造成很多隐患 --> 苹果公司给出了 ...
随机推荐
- Lua面向对象
lua中的table就是一种对象,但是如果直接使用仍然会存在大量的问题,如下: 1 Account = {balance = 0}2 function Account.withdraw(v)3 Acc ...
- CNUOJ 535 黑魔法师之门
先摆出题 难度级别:C: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 背景: 经过了16个工作日的紧张忙碌,未来的人类终于收集到了足够的能源 ...
- MySQL 事务
MySQL 事务主要用于处理操作量大,复杂度高的数据.比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成 ...
- jcl-over-slf4j log桥接工具简介
ava 界里有许多实现日志功能的工具,最早得到广泛使用的是 log4j,许多应用程序的日志部分都交给了 log4j,不过作为组件开发者,他们希望自己的组件不要紧紧依赖某一个工具,毕竟在同一个时候还有很 ...
- eclipse java项目中明明引入了jar包 为什么项目启动的时候不能找到jar包 项目中已经 引入了 com.branchitech.app 包 ,但时tomcat启动的时候还是报错? java.lang.ClassNotFoundException: com.branchitech.app.startup.AppStartupContextListener java.lang.ClassN
eclipse java项目中明明引入了jar包 为什么项目启动的时候不能找到jar包 项目中已经 引入了 com.branchitech.app 包 ,但时tomcat启动的时候还是报错?java. ...
- 奥迪--A3
-型号:A3 -价格:18-28W -动力:1.4T/1.8T -变速箱:7挡双离合 -长宽高:4.32,1.79,1.43(Limousine:4.46,1.80,1.42) -油箱:50L -发动 ...
- 安装运行Hadoop
1 准备环境 1.1 Ubuntu 或者 VMware Workstation Pro+Ubuntu 1.2 Jdk 1.3 eclipse 或其他开发工具(可选) 2 安装Hadoop 2.1 从h ...
- pt-archiver使用
pt-archiver工具其实就是用来清理,归档数据用的 一.归档前的准备需要配置client字符集为utf-8,如果你用了utf-8的编码,防止归档数据为乱码[client]default-char ...
- VC++获取IDC_EDIT的7种方法
VC++获取IDC_EDIT的7种方法 http://blog.csdn.net/baizengfei/article/details/7997618 //第一种方法 int number1, num ...
- opencv支持的机器学习算法
CXCORE库: Mahalanobis距离: K均值: CV库: 人脸检测/Haar分类器 ML库: 正态朴素贝叶斯分类器: 决策树: Boosting: 随机森林: EM算法: K近邻(KNN): ...