前言:本文章第一时间出现在一个程序猿的秘密基地专题中,如果您喜欢类似的文章,请您点击一个程序猿的秘密基地进行关注,在以后的日子里与小编共同成长!
1.GCD是什么?
2.GCD的优势
3.GCD的核心理念
4.GCD的队列类型
5.自定义串行和并行队列
6.全局并行队列的优先级
7.主线程中的串行队列
8.调度组
9.调度组(扩展)
10.造成线程死锁的两种情况
11.线程锁(NSLock)
12.通过GCD实现单例类(ARC)
13.通过GCD实现单例类(MRC)
1.GCD是什么?
GCD全称Grand Central Dispath(宏大的的中央调度),是苹果开发的一种支持并行操作的机制。
它的主要部件是一个FIFO队列和一个线程池,前者用来添加任务,后者用来执行任务。
GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行(但不
保证一定先执行结束)。
GCD中的函数大多数都以dispatch开头
2.GCD的优势
1.它是苹果公司为多核的并行运算提出的解决方案
2.它在工作的时候会自动利用更多的处理器核心
3.不用关心线程代码的实现,即不需要关心什么时候开启线程、关闭线程,GCD会负责创建线程调度你的任务
4.只需要创建出来你要执行的任务,然后把任务添加到适当的队列中
3.GCD的核心理念
将长期运行的任务拆分成多个工作单元,并把这些工作单元添加调度队列
4.GCD的队列类型
分为两种类型:
1.串行队列(需要自己创建队列):排成一队,一次只能执行一个任务,当前的任务完成之后开始出列,
启动下一个任务
2.并行队列(不需要自己创建队列):同时排成N个队,可以让多个任务同时执行,即启动多个线程同时
执行任务,并发功能只有在异步(dispatch_async)函数下才有效
ps:并行队列依旧按照任务添加的顺序启动任务,但是,后一个任务无须等待前一个任务执行完毕,而是
启动第一个任务后,立即启动下一个任务。至于同一时刻允许同时运行多少个任务由系统决定,任务各自
运行在并行队列为它们提供的独立线程上,并行队列中同时运行多少个任务,就必须维护多少个线程。
5.自定义串行和并行队列。
/*
* (1)串行队列,添加同步任务
* 串行队列中的任务按照添加顺序执行,不会开启新线程.
*/
- (void)demo1
{
//创建串行队列
//参数1:表示队列的标识符,一般以反域名的形式命名
//参数2:队列样式,DISPATCH_QUEUE_SERIAL或者NULL,表示串行队列
dispatch_queue_t mySerialQueue = dispatch_queue_create("com.zhiyou.aaa", DISPATCH_QUEUE_SERIAL);
//将任务添加到队列中.
//sync(同步):阻塞当前线程,当block块中的任务执行完毕之后,再执行后续代码
NSLog(@"111111");
dispatch_sync(mySerialQueue, ^{
NSLog(@"--------%@",[NSThread currentThread]);
for (int i = 0; i < 100; i++)
{
NSLog(@"2222222");
}
});
dispatch_sync(mySerialQueue, ^{
NSLog(@"--------%@",[NSThread currentThread]);
for (int i = 0; i < 100; i++)
{
NSLog(@"33333333");
}
});
for (int i = 0; i < 100; i++)
{
NSLog(@"44444444");
}
}
/*
* (2)串行队列,添加异步任务.
* 只开辟一条新线程,新线程中的任务还是按照添加顺序执行,但是与主线程中任务是并发执行.
*/
- (void)demo2
{
dispatch_queue_t mySerialQueue = dispatch_queue_create("com.zhiyou.bbb", DISPATCH_QUEUE_SERIAL);
//async(异步):不阻塞当前线程.block块中的任务与后续代码同时执行.
NSLog(@"1111111");
dispatch_async(mySerialQueue, ^{
NSLog(@"------%@",[NSThread currentThread]);
for (int i = 0; i < 50; i++)
{
NSLog(@"22222");
}
});
dispatch_async(mySerialQueue, ^{
NSLog(@"------%@",[NSThread currentThread]);
for (int i = 0; i < 50; i++)
{
NSLog(@"33333");
}
});
for (int i = 0; i < 50; i++)
{
NSLog(@"44444");
}
}
/*
* (3)并行队列,添加同步任务(并无任何意义)
* 不会开辟新线程,任务按添加顺序执行.
*/
- (void)demo3
{
//DISPATCH_QUEUE_CONCURRENT:表示并行队列
dispatch_queue_t myConcurrentQurue = dispatch_queue_create("com.zhiyou.ccc", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1111");
dispatch_sync(myConcurrentQurue, ^{
NSLog(@"-----%@",[NSThread currentThread]);
for (int i = 0; i < 50; i++)
{
NSLog(@"2222");
}
});
dispatch_sync(myConcurrentQurue, ^{
NSLog(@"-----%@",[NSThread currentThread]);
for (int i = 0; i < 50; i++)
{
NSLog(@"333");
}
});
dispatch_sync(myConcurrentQurue, ^{
NSLog(@"-----%@",[NSThread currentThread]);
for (int i = 0; i < 50; i++)
{
NSLog(@"444");
}
});
for (int i = 0; i < 50; i++)
{
NSLog(@"5555");
}
}
/*
* 并行队列,添加异步任务
* 会开辟多条新线程,任务并发执行.
*/
- (void)demo4
{
dispatch_queue_t myConcurrentQurue = dispatch_queue_create("com.zhiyou.ccc", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1111");
dispatch_async(myConcurrentQurue, ^{
NSLog(@"-----%@",[NSThread currentThread]);
for (int i = 0; i < 50; i++)
{
NSLog(@"2222");
}
});
dispatch_async(myConcurrentQurue, ^{
NSLog(@"-----%@",[NSThread currentThread]);
for (int i = 0; i < 50; i++)
{
NSLog(@"333");
}
});
dispatch_async(myConcurrentQurue, ^{
NSLog(@"-----%@",[NSThread currentThread]);
for (int i = 0; i < 50; i++)
{
NSLog(@"444");
}
});
for (int i = 0; i < 50; i++)
{
NSLog(@"5555");
}
}
6.全局并行队列的优先级
/*
* 2.运行在分线程的四个优先级不同全局并行队列,globalQueue
* 开辟多条线程,并发执行任务
*/
- (void)demo5
{
//获取 globalQueue
//参数1:表示队列的优先级
//参数2:预留参数,设置为0.
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_queue_t globalQueue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t globalQueue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(globalQueue, ^{
NSLog(@"------%@",[NSThread currentThread]);
for (int i = 0; i < 5; i++)
{
NSLog(@"2222");
}
});
dispatch_async(globalQueue1, ^{
NSLog(@"------%@",[NSThread currentThread]);
for (int i = 0; i < 5; i++)
{
NSLog(@"1111111");
}
});
dispatch_async(globalQueue2, ^{
NSLog(@"------%@",[NSThread currentThread]);
for (int i = 0; i < 5; i++)
{
NSLog(@"000000");
}
});
for (int i = 0; i < 5; i++)
{
NSLog(@"5555");
}
}
7.主线程中的串行队列
PS:在主线程中,主队列中使用同步任务会造成死锁
/*
主队列
运行在主线程的串行队列,mainQueue。
*/
- (void)demo6
{
dispatch_queue_t mainQueue = dispatch_get_main_queue();
NSLog(@"11111");
dispatch_async(mainQueue, ^{
NSLog(@"-----%@",[NSThread currentThread]);
for (int i = 0; i < 20; i++)
{
NSLog(@"22222");
}
});
for (int i = 0; i < 20; i++)
{
NSLog(@"33333");
}
}
8.调度组
// 群组-统一监控一组任务
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
// 添加任务
// group 负责监控任务,queue 负责调度任务
dispatch_group_async(group, q, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"任务1 %@", [NSThread currentThread]);
});
dispatch_group_async(group, q, ^{
NSLog(@"任务2 %@", [NSThread currentThread]);
});
dispatch_group_async(group, q, ^{
NSLog(@"任务3 %@", [NSThread currentThread]);
});
// 监听所有任务完成 - 等到 group 中的所有任务执行完毕后,"由队列调度 block 中的任务异步执行!"
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 修改为主队列,后台批量下载,结束后,主线程统一更新UI
NSLog(@"OK %@", [NSThread currentThread]);
});
NSLog(@"come here");
9.调度组(扩展)
调度组中还有一个添加任务的函数:
dispatch_group_enter(dispatch_group_t group)
dispatch_group_leave(dispatch_group_t group)
这两个函数要配对出现 例如:
// 群组-统一监控一组任务
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
// 1> 入组 -> 之后的 block 会被 group 监听
// dispatch_group_enter 一定和 dispatch_group_leave 要配对出现
dispatch_group_enter(group);
dispatch_async(q, ^{
NSLog(@"task1 %@", [NSThread currentThread]);
// block 的末尾,所有任务执行完毕后,添加一个出组
dispatch_group_leave(group);
});
// 再次入组
dispatch_group_enter(group);
dispatch_async(q, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"task2 %@", [NSThread currentThread]);
// block 的末尾,所有任务执行完毕后,添加一个出组
dispatch_group_leave(group);
});
// 群组结束
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"OVER");
});
NSLog(@"come here");
10.造成线程死锁的两种情况
《1》请回看本文中第七条 条目下的注释,讲述的是第一种死锁情况。
《2》串行队列在使用的过程中容易出现死锁,调用 同步函数的队列 和 同步函数添加任务的目标队列 是同一个队列.
如果不是同一个队列, 是没有问题的.
dispatch_queue_t queue = dispatch_queue_create("com.zhiyou.queue", DISPATCH_QUEUE_SERIAL);
NSLog(@"任务一");
dispatch_sync(queue, ^{
NSLog(@"任务二");
//queue队列在调用同步函数
dispatch_sync(queue, ^{
NSLog(@"任务三");
});
NSLog(@"任务四");
});
NSLog(@"任务五");
11.线程锁(NSLock)
//Demo介绍:模拟售票员买票,展示不加锁和加锁的区别
#import "ViewController.h"
@interface ViewController ()
{
NSInteger _ticketNum;
NSLock *_lock;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self sellTicket];
}
- (void)sellTicket
{
//所剩下的票数
_ticketNum = 6;
//创建锁
_lock = [[NSLock alloc]init];
NSThread *theard1 = [[NSThread alloc]initWithTarget:self selector:@selector(buyTicket) object:nil];
theard1.name = @"售票员1";
[theard1 start];
NSThread *theard2 = [[NSThread alloc]initWithTarget:self selector:@selector(buyTicket) object:nil];
theard2.name = @"售票员2";
[theard2 start];
NSThread *theard3 = [[NSThread alloc]initWithTarget:self selector:@selector(buyTicket) object:nil];
theard3.name = @"售票员3";
[theard3 start];
}
- (void)buyTicket
{
while (YES)
{
//锁
// [_lock lock];
if (_ticketNum > 0)
{
[NSThread sleepForTimeInterval:0.1];
_ticketNum--;
NSLog(@"%@卖了一张票,还剩余 %d 张票",[NSThread currentThread].name,_ticketNum);
}
else
{
return;
}
//解锁
// [_lock unlock];
}
}
@end
下面是我捕捉到的不加锁控制面板的输入️
·
情况一:错序
情景二:出现两个售票员同时操作同一张票,导致票数错误
12.通过GCD实现单例类(ARC)
#import "Singleton.h"
static Singleton *singleton = nil;
@implementation Singleton
//通过GCD来实现单例模式
+ (instancetype)shareSingleton
{
//参数1:谓词,用来判断block块是否已经被执行.
//参数2:只会被调用一次的block
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[super allocWithZone:NULL]init];
});
return singleton;
}
+ (id)allocWithZone:(struct _NSZone *)zone
{
return [self shareSingleton];
}
@end
13.通过GCD实现单例类(MRC)
danlilei.h
#import <Foundation/Foundation.h>
@interface danlilei : NSObject
+(instancetype)danlilei;
@end
danlilei.m
//需要确保单例类的原则:一个类只有一个对象。所以要重写以下所有方法
#import "danlilei.h"
static danlilei4*danli=nil;
@implementation danlilei
+(instancetype)danlilei
{
@synchronized(self)
{
danli=[danlilei4 new];
}
return danli;
}
-(id)init
{
self=[super init];
if (self)
{
}
return self;
}
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
return [self danlilei];
}
+(id)copyWithZone:(struct _NSZone *)zone
{
return [self danlilei];
}
-(instancetype)retain
{
return danli;
}
-(oneway void)release
{
}
-(id)autorelease
{
return danli;
}
-(NSUInteger)retainCount
{
return 1;
}
@end
网友评论