images
GCD会自动将队列中的任务取出,放到对应的线程,任务的取出遵循FIFO
,即先入先出队列,First Input First Output
的缩写。
先进入的任务先完成并结束,再执行后面的任务。
同步函数和异步函数,并发队列和串行队列
用同步的方式执行任务:在当前线程中可立即执行任务,不具备开启线程的能力
用异步的方式执行任务:在当前线程结束时执行任务,具备开启新的线程的能力
-
并发队列:允许多个任务同时执行
-
串行队列:一个任务执行完毕后,再执行下一个任务
创建并发/串行队列代码:
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_get_main_queue();
// 创建串行队列 serial 串行 concurrent并发
queueSerial = dispatch_queue_create(“searial.whenbar.com”, DISPATCH_QUEUE_SERIAL);
//创建并行队列
// 参1:const char *label 队列名称
// 参2:dispatch_queue_attr_t attr 队列类型
queueConcurrent = dispatch_queue_create(“concurrent.whenbar.com”, DISPATCH_QUEUE_CONCURRENT);
}
//1 获得主队列
-(void)runqueueMain
{
// 获取主队列 在主队列中的任务都会在主线程中执行。
dispatch_queue_t queueMain = dispatch_get_main_queue();
}
//2. 创建串行队列
-(void)runqueueSerial
{
// GCD同步函数串行队列(立即执行,当前线程)
// 参1: dispatch_queue_t queue 队列
// 参2: 任务
dispatch_sync(queueSerial, ^{
for (NSInteger i = 0; i < 10; i++) {
NSLog(@“~~~%ld %@”,i, [NSThread currentThread]);
}
});
// 异步函数串行队列 (另开线程,多个任务按顺序执行)
dispatch_async(queueSerial, ^{
dispatch_async(queueSerial, ^{
for (NSInteger i = 0; i < 10; i++) {
NSLog(@“~~~%ld %@”,i, [NSThread currentThread]);
}
});
dispatch_async(queueSerial, ^{
for (NSInteger i = 0; i < 10; i++) {
NSLog(@“~~~%ld %@”,i, [NSThread currentThread]);
}
});
dispatch_async(queueSerial, ^{
for (NSInteger i = 0; i < 10; i++) {
NSLog(@“~~~%ld %@”,i, [NSThread currentThread]);
}
});
});
}
//3. 创建并发队列
-(void)runqueueConcurrent
{
// 同步函数并行队列(立即执行,当前线程)
dispatch_sync(queueConcurrent, ^{
for (NSInteger i = 0; i < 10; i++) {
NSLog(@“~~~%ld %@”,i, [NSThread currentThread]);
}
});
// 异步函数并行队列 (另开线程,多个任务一起执行)
dispatch_async(queueConcurrent, ^{
dispatch_async(queueConcurrent, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@“~~~%ld %@”,i, [NSThread currentThread]);
}
});
dispatch_async(queueConcurrent, ^{
for (NSInteger i = 0; i < 6; i++) {
NSLog(@“~~~%ld %@”,i, [NSThread currentThread]);
}
});
dispatch_async(queueConcurrent, ^{
for (NSInteger i = 0; i < 7; i++) {
NSLog(@“~~~%ld %@”,i, [NSThread currentThread]);
}
});
});
}
//4. 创建全局队列
-(void)runqueueGlobal
{
// 获取全局队列 全局队列是并发队列
// 参1:队列的优先级
// 参2:0(以后可能用到的参数)//#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高\
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)\
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低\
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
dispatch_queue_t queueGlobal = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
}
// 主队列:(任何一个任务只要在主队列中,都会加入到主线程的队列中执行)复制代码
TIPS: 注意
使用sync函数(同步函数)往当前串行队列中添加任务,会卡住当前的串行队列
解释:使用同步函数添加任务 A 到串行队列,说明要在当前串行队列立即执行任务 A ,任务 A 执行完后,才会执行任务 A 后面的代码。但当前队列是串行队列,也就是说任务 A 必须等到当前串行队列中正在执行的任务 B 完成之后才能执行,因此又必须先执行任务 A 中立即执行任务,又要必须等到任务 B 执行完以后才能执行下一个任务,所以就会卡死。你等我,我等你,谁也无法执行。
####GCD实现线程通信
小项目:下载图片
代码如下:
// 获取图片的url
NSURL *url = [NSURL URLWithString:@“http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg”];
// 开启线程下载图片
dispatch_queue_t queue = dispatch_queue_create(“111”, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
// 下载完成后返回主线程显示图片
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
});复制代码
————————————————————————————————————————
GCD其他常用函数
image
//----------------- 队列组 -----------------------------
//队列组可以将很多队列添加到一个组里,这样做的好处是,当这个组里所有的任务都执行完了,队列组会通过一个方法通知我们。下面是使用方法,这是一个很实用的功能。
-(void)rungroup
{
//1.创建队列组
dispatch_group_t group=dispatch_group_create();
//2.创建队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
//3.多次使用队列组的方法执行任务, 只有异步方法
//3.1.执行3次循环
dispatch_group_async(group,queue,^{
for (NSInteger i = 0; i< 3; i++){
NSLog(@“group-01 - %@”, [NSThread currentThread]);
}
});
//3.2.主队列执行8次循环
dispatch_group_async(group, dispatch_get_main_queue(), ^{
for (NSInteger i=0;i<8;i++) {
NSLog(@“group-02 - %@”, [NSThread currentThread]);
}
});
//3.3.执行5次循环
dispatch_group_async(group, queue, ^{
for(NSInteger i=0;i<5;i++) {
NSLog(@“group-03 - %@”, [NSThread currentThread]);
}
});
//4.都完成后会自动通知
dispatch_group_notify(group,dispatch_get_main_queue(),^{
NSLog(@“完成 - %@”, [NSThread currentThread]);
});
}复制代码
dispatch_barrier
栅栏
// 1.barrier : 在barrier前面的先执行,然后再执行barrier,然后再执行barrier后面的 barrier的queue不能是全局的并发队列
dispatch_queue_t queue = dispatch_queue_create(“11”, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@“%@–1”, [NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@“%@–2”, [NSThread currentThread]);
}
});
dispatch_barrier_async(queue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@“%@–3”, [NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@“%@–4”, [NSThread currentThread]);
}
});
// dispatch_after 延迟执行
// 延迟执行
// 方法1
[self performSelector:@selector(run:) withObject:@“参数” afterDelay:2.0];
// 方法2
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
for (NSInteger i = 0; i < 100; i++) {
NSLog(@“%@”, [NSThread currentThread]);
}
});
// 方法3
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run:) userInfo:nil repeats:NO];
dispatch_once 整个程序运行中执行一次
// 整个程序中只执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 一次性代码
});复制代码
思考题:以下函数输出的结果是什么?
image
以下的代码输出是什么呢
image
作用:实现某个类的单例对象
单例模式:在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次)
//--------------单例模式--------------------
#if __has_feature(objc_instancetype)
#undef AS_SINGLETON
#define AS_SINGLETON( … ) \
- (instancetype)sharedInstance; \
- (instancetype)sharedInstance;
#undef DEF_SINGLETON
#define DEF_SINGLETON \
- (instancetype)sharedInstance \
{ \
return [[self class] sharedInstance]; \
} \
- (instancetype)sharedInstance \
{ \
static dispatch_once_t once; \
static id singleton; \
dispatch_once( &once, ^{ singleton = [[self alloc] init]; } ); \
return singleton; \
}
#undef DEF_SINGLETON
#define DEF_SINGLETON( … ) \
- (instancetype)sharedInstance \
{ \
return [[self class] sharedInstance]; \
} \
- (instancetype)sharedInstance \
{ \
static dispatch_once_t once; \
static id singleton; \
dispatch_once( &once, ^{ singleton = [[self alloc] init]; } ); \
return singleton; \
}
#else // #if __has_feature(objc_instancetype)
#undef AS_SINGLETON
#define AS_SINGLETON( __class ) \
- (__class *)sharedInstance; \
- (__class *)sharedInstance;
#undef DEF_SINGLETON
#define DEF_SINGLETON( __class ) \
- (__class *)sharedInstance \
{ \
return [__class sharedInstance]; \
} \
- (__class *)sharedInstance \
{ \
static dispatch_once_t once; \
static __class * singleton; \
dispatch_once( &once, ^{ singleton = [[[self class] alloc] init]; } ); \
return singleton; \
}
#endif // #if __has_feature(objc_instancetype)
#import “gcdfunViewController.h”
#pragma mark - 单例模式👆 👇
@interface Person:NSObject
//+ (instancetype)shareInstance;
AS_SINGLETON(Person)
@end
@implementation Person
DEF_SINGLETON(Person)
/*
- (instancetype)shareInstance
{
static id _person;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_person = [[super alloc] init];
});
return _person;
}
*/
- (instancetype)allocWithZone:(struct _NSZone *)zone
{
static id _person;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_person = [super allocWithZone:zone];
});
return _person;
}
- (id)copy
{
return [Person sharedInstance];
}
@end复制代码
开发中一般自定义成宏,比较方便,一行代码搞定。
dispatch_apply
快速迭代
//示例小程序:将一个文件夹中的图片剪切到另一个文件夹
-(void)testdispatch_apply
{
// 将图片剪切到另一个文件夹里
NSString *from = @“/Users/Ammar/Pictures/壁纸”;
NSString *to = @“/Users/Ammar/Pictures/to”;
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *subPaths = [manager subpathsAtPath:from];
// 快速迭代
dispatch_apply(subPaths.count, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
NSLog(@“%@ - %zd”, [NSThread currentThread], index);
NSString *subPath = subPaths[index];
NSString *fromPath = [from stringByAppendingPathComponent:subPath];
NSString *toPath = [to stringByAppendingPathComponent:subPath];
// 剪切
[manager moveItemAtPath:fromPath toPath:toPath error:nil];
NSLog(@“%@—%zd”, [NSThread currentThread], index);
});
//作用是把指定次数指定的block添加到queue中, 第一个参数是迭代次数,第二个是所在的队列,第三个是当前索引,dispatch_apply可以利用多核的优势,所以输出的index顺序不是一定的
dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
NSLog(@“dispatch_apply %zd”,index);
});
/*输出结果 无序的
2016-02-15 10:15:21.229 多线程[4346:48391] dispatch_apply 0
2016-02-15 10:15:21.229 多线程[4346:48784] dispatch_apply 1
2016-02-15 10:15:21.230 多线程[4346:48830] dispatch_apply 2
2016-02-15 10:15:21.230 多线程[4346:48391] dispatch_apply 4
2016-02-15 10:15:21.230 多线程[4346:48829] dispatch_apply 3
2016-02-15 10:15:21.231 多线程[4346:48391] dispatch_apply 6
2016-02-15 10:15:21.231 多线程[4346:48391] dispatch_apply 9
2016-02-15 10:15:21.230 多线程[4346:48784] dispatch_apply 5
2016-02-15 10:15:21.231 多线程[4346:48829] dispatch_apply 8
2016-02-15 10:15:21.231 多线程[4346:48830] dispatch_apply 7
*/
}复制代码
dispatch_group
队列组
示例小程序:需求下载图片1 下载图片2 将图片1和图片2合成新的图片
// 创建队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 创建组
dispatch_group_t group = dispatch_group_create();
// 用组队列下载图片1
dispatch_group_async(group, queue, ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@“http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg”]];
self.image1 = [UIImage imageWithData:data];
NSLog(@“1%@”, [NSThread currentThread]);
});
// 用组队列下载图片2
dispatch_group_async(group, queue, ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@“http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg”]];
self.image2 = [UIImage imageWithData:data];
NSLog(@“2%@”, [NSThread currentThread]);
});
// 将图片1和图片2合成一张图片
dispatch_group_notify(group, queue, ^{
CGFloat imageW = self.imageView.bounds.size.width;
CGFloat imageH = self.imageView.bounds.size.height;
// 开启位图上下文
UIGraphicsBeginImageContext(self.imageView.bounds.size);
// 画图
[self.image1 drawInRect:CGRectMake(0, 0, imageW * 0.5, imageH)];
[self.image2 drawInRect:CGRectMake(imageW * 0.5, 0, imageW * 0.5, imageH)];
// 将图片取出
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 关闭图形上下文
UIGraphicsEndImageContext();
// 在主线程上显示图片
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
NSLog(@“3%@”, [NSThread currentThread]);
});复制代码
####GCD定时器
GCD定时器不受Mode影响因此比NSTimer要准确
#pragma mark - 定时器
//做定时器或倒计时
-(IBAction)buttonTap:(id)sender
{
UIButton * button = (UIButton *)sender;
button.enabled = NO;
// 1.创建一个定时器源
// 参1:类型定时器
// 参2:句柄
// 参3:mask传0
// 参4:队列 (注意:dispatch_source_t本质是OC对象,表示源)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 严谨起见,时间间隔需要用单位int64_t,做乘法以后单位就变了
// 下面这句代码表示回调函数时间间隔是多少
int64_t interval = (int64_t)(1.0 * NSEC_PER_SEC);
// 如何设置开始时间 CGD给我们了一个设置时间的方法
// 参1:dispatch_time_t when 传一个时间, delta是增量
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)); // 从现在起0秒后开始
// 参1:timer
// 参2:开始时间
// 参3:时间间隔
// 参4:传0 不需要 DISPATCH_TIME_NOW 表示现在 GCD 时间用 NS 表示
dispatch_source_set_timer(timer, start, interval, 0);
__block int count = 60;
// 3.设置回调(即每次间隔要做什么事情)
dispatch_source_set_event_handler(timer, ^{
NSLog(@“----------------%@”, [NSThread currentThread]);
// 如果希望做5次就停掉
count – ;
dispatch_async(dispatch_get_main_queue(), ^{
if (count == 0) {
dispatch_source_cancel(timer);
[button setTitle:@“点击倒计时” forState:UIControlStateNormal];
button.enabled = YES;
}
else
{
[button setTitle:[NSString stringWithFormat:@“%d”,count] forState:UIControlStateNormal];
[button setTitle:[NSString stringWithFormat:@“%d”,count] forState:UIControlStateDisabled];
}
});
});
// 4.启动定时器 (恢复)
dispatch_resume(timer);
}复制代码
gcd 还有一些其他的函数 下次再深入!
————————————————————————————————————————————————————————————————————————————————
讲完 GCD 就该讲讲 NSOperation,它是 GCD 的面向对象的封装,使用起来也更方便,
-
NSOperation实现多线程
-
NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类
-
NSInvocationOperation
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
最后
Java架构学习技术内容包含有:Spring,Dubbo,MyBatis, RPC, 源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。
还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书+2021年最新大厂面试题。
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
大家的负担。**
[外链图片转存中…(img-Y6gHXfEZ-1712156864962)]
[外链图片转存中…(img-j3XXbcjf-1712156864963)]
[外链图片转存中…(img-r0RdSIbu-1712156864964)]
[外链图片转存中…(img-p8ejdhdT-1712156864964)]
[外链图片转存中…(img-iPKtGk3o-1712156864964)]
[外链图片转存中…(img-0ouzx0C6-1712156864965)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-T7LrKg3D-1712156864966)]
最后
Java架构学习技术内容包含有:Spring,Dubbo,MyBatis, RPC, 源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。
还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书+2021年最新大厂面试题。
[外链图片转存中…(img-HfL8iJ1J-1712156864966)]
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算