转自 http://www.cnblogs.com/junior-ios/p/4694508.html
串行队列
先进先出
的方式,顺序
调度队列中的任务执行dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", NULL);
/**
提问:是否开线程?是否顺序执行?come here 的位置?
*/
- (void)gcdDemo1 {
// 1. 队列
dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", DISPATCH_QUEUE_SERIAL);
// 2. 执行任务
for (int i = 0; i < 10; ++i) {
NSLog(@"--- %d", i);
dispatch_sync(q, ^{
NSLog(@"%@ - %d", [NSThread currentThread], i);
});
}
NSLog(@"come here");
}
/**
提问:是否开线程?是否顺序执行?come here 的位置?
*/
- (void)gcdDemo2 {
// 1. 队列
dispatch_queue_t q = dispatch_queue_create("itheima", NULL);
// 2. 执行任务
for (int i = 0; i < 10; ++i) {
NSLog(@"--- %@ %d", [NSThread currentThread], i);
dispatch_async(q, ^{
NSLog(@"%@ - %d", [NSThread currentThread], i);
});
}
NSLog(@"come here");
}
先进先出
的方式,并发
调度队列中的任务执行同步
执行的,会等待任务执行完成后,再调度后续的任务异步
执行的,同时底层线程池有可用的线程资源,会再新的线程调度后续任务的执行dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", DISPATCH_QUEUE_CONCURRENT);
/**
提问:是否开线程?是否顺序执行?come here 的位置?
*/
- (void)gcdDemo3 {
// 1. 队列
dispatch_queue_t q = dispatch_queue_create("itheima", DISPATCH_QUEUE_CONCURRENT);
// 2. 执行任务
for (int i = 0; i < 10; ++i) {
dispatch_async(q, ^{
NSLog(@"%@ - %d", [NSThread currentThread], i);
});
}
NSLog(@"come here");
}
/**
提问:是否开线程?是否顺序执行?come here 的位置?
*/
- (void)gcdDemo4 {
// 1. 队列
dispatch_queue_t q = dispatch_queue_create("itheima", DISPATCH_QUEUE_CONCURRENT);
// 2. 执行任务
for (int i = 0; i < 10; ++i) {
dispatch_sync(q, ^{
NSLog(@"%@ - %d", [NSThread currentThread], i);
});
NSLog(@"---> %i", i);
}
NSLog(@"come here");
}
先进先出
的方式,在主线程空闲时
才会调度队列中的任务在主线程执行dispatch_queue_t queue = dispatch_get_main_queue();
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self gcdDemo1];
[NSThread sleepForTimeInterval:1];
NSLog(@"over");
}
- (void)gcdDemo1 {
dispatch_queue_t queue = dispatch_get_main_queue();
for (int i = 0; i < 10; ++i) {
dispatch_async(queue, ^{
NSLog(@"%@ - %d", [NSThread currentThread], i);
});
NSLog(@"---> %d", i);
}
NSLog(@"come here");
}
2015-07-13 00:44:57.241 testGCD线程[37988:581895] ---> 0
2015-07-13 00:44:57.242 testGCD线程[37988:581895] ---> 1
2015-07-13 00:44:57.242 testGCD线程[37988:581895] ---> 2
2015-07-13 00:44:57.242 testGCD线程[37988:581895] ---> 3
2015-07-13 00:44:57.242 testGCD线程[37988:581895] ---> 4
2015-07-13 00:44:57.242 testGCD线程[37988:581895] ---> 5
2015-07-13 00:44:57.242 testGCD线程[37988:581895] ---> 6
2015-07-13 00:44:57.242 testGCD线程[37988:581895] ---> 7
2015-07-13 00:44:57.242 testGCD线程[37988:581895] ---> 8
2015-07-13 00:44:57.242 testGCD线程[37988:581895] ---> 9
2015-07-13 00:44:57.242 testGCD线程[37988:581895] come here
2015-07-13 00:44:58.243 testGCD线程[37988:581895] over
2015-07-13 00:44:58.244 testGCD线程[37988:581895] {number = 1, name = main} - 0
2015-07-13 00:44:58.244 testGCD线程[37988:581895] {number = 1, name = main} - 1
2015-07-13 00:44:58.244 testGCD线程[37988:581895] {number = 1, name = main} - 2
2015-07-13 00:44:58.244 testGCD线程[37988:581895] {number = 1, name = main} - 3
2015-07-13 00:44:58.245 testGCD线程[37988:581895] {number = 1, name = main} - 4
2015-07-13 00:44:58.245 testGCD线程[37988:581895] {number = 1, name = main} - 5
2015-07-13 00:44:58.245 testGCD线程[37988:581895] {number = 1, name = main} - 6
2015-07-13 00:44:58.245 testGCD线程[37988:581895] {number = 1, name = main} - 7
2015-07-13 00:44:58.245 testGCD线程[37988:581895] {number = 1, name = main} - 8
2015-07-13 00:44:58.245 testGCD线程[37988:581895] {number = 1, name = main} - 9
在
主线程空闲时
才会调度队列中的任务在主线程执行
// MARK: 主队列,同步任务
- (void)gcdDemo6 {
// 1. 队列
dispatch_queue_t q = dispatch_get_main_queue();
NSLog(@"!!!");
// 2. 同步
dispatch_sync(q, ^{
NSLog(@"%@", [NSThread currentThread]);
});
NSLog(@"come here");
}
主队列
和主线程
相互等待会造成死锁
同步任务,可以让其他异步执行的任务,
依赖
某一个同步任务
例如:在用户登录之后,再异步下载文件!
- (void)gcdDemo1 {
dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
NSLog(@"登录 %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"下载 A %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"下载 B %@", [NSThread currentThread]);
});
}
- (void)gcdDemo2 {
dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", DISPATCH_QUEUE_CONCURRENT);
void (^task)() = ^{
dispatch_sync(queue, ^{
NSLog(@"登录 %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"下载 A %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"下载 B %@", [NSThread currentThread]);
});
};
dispatch_async(queue, task);
}
- (void)gcdDemo3 {
dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", DISPATCH_QUEUE_CONCURRENT);
void (^task)() = ^ {
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"死?");
});
};
dispatch_async(queue, task);
}
主队列在
主线程空闲时
才会调度队列中的任务在主线程执行Barrier 异步
非线程安全
的对象进行更新大规模的 I/O
操作@interface ViewController () {
// 加载照片队列
dispatch_queue_t _photoQueue;
}
@property (nonatomic, strong) NSMutableArray *photoList;
@end
- (NSMutableArray *)photoList {
if (_photoList == nil) {
_photoList = [[NSMutableArray alloc] init];
}
return _photoList;
}
NSMutableArray
是非线程安全的
- (void)viewDidLoad {
[super viewDidLoad];
_photoQueue = dispatch_queue_create("com.itheima.com", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 20; ++i) {
[self loadPhotos:i];
}
}
- (void)loadPhotos:(int)index {
dispatch_async(_photoQueue, ^{
[NSThread sleepForTimeInterval:1.0];
NSString *fileName = [NSString stringWithFormat:@"%02d.jpg", index % 10 + 1];
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
UIImage *image = [UIImage imageWithContentsOfFile:path];
[self.photoList addObject:image];
NSLog(@"添加照片 %@", fileName);
});
}
运行测试
由于 NSMutableArray
是非线程安全的,如果出现两个线程在同一时间向数组中添加对象,会出现程序崩溃的情况
解决办法
NSLog(@"添加照片 %@", fileName);
dispatch_barrier_async(_photoQueue, ^{
[self.photoList addObject:image];
NSLog(@"OK %@", [NSThread currentThread]);
});
使用
dispatch_barrier_async
添加的 block 会在之前添加的 block 全部运行结束之后,才在同一个线程顺序执行,从而保证对非线程安全的对象进行正确的操作!
注意:
dispatch_barrier_async
必须使用自定义队列,否则执行效果和全局队列一致
并发队列
一致NSThread
的 name
属性作用类似dispatch_release(q);
释放相应的对象dispatch_barrier
必须使用自定义的并发队列/**
提问:是否开线程?是否顺序执行?come here 的位置?
*/
- (void)gcdDemo8 {
// 1. 队列
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
// 2. 执行任务
for (int i = 0; i < 10; ++i) {
dispatch_async(q, ^{
NSLog(@"%@ - %d", [NSThread currentThread], i);
});
}
NSLog(@"come here");
}
运行效果与并发队列相同
服务质量(队列对任务调度的优先级)/iOS 7.0 之前,是优先级
QOS_CLASS_USER_INTERACTIVE
0x21, 用户交互(希望最快完成-不能用太耗时的操作)QOS_CLASS_USER_INITIATED
0x19, 用户期望(希望快,也不能太耗时)QOS_CLASS_DEFAULT
0x15, 默认(用来底层重置队列使用的,不是给程序员用的)QOS_CLASS_UTILITY
0x11, 实用工具(专门用来处理耗时操作!)QOS_CLASS_BACKGROUND
0x09, 后台QOS_CLASS_UNSPECIFIED
0x00, 未指定,可以和iOS 7.0 适配DISPATCH_QUEUE_PRIORITY_HIGH
2 高优先级DISPATCH_QUEUE_PRIORITY_DEFAULT
0 默认优先级DISPATCH_QUEUE_PRIORITY_LOW
(-2) 低优先级DISPATCH_QUEUE_PRIORITY_BACKGROUND
INT16_MIN 后台优先级为未来保留使用的,应该永远传入0
结论:如果要适配 iOS 7.0 & 8.0,使用以下代码:
dispatch_get_global_queue(0, 0);
延迟操作
// MARK: - 延迟执行
- (void)delay {
/**
从现在开始,经过多少纳秒,由"队列"调度异步执行 block 中的代码
参数
1. when 从现在开始,经过多少纳秒
2. queue 队列
3. block 异步执行的任务
*/
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC));
void (^task)() = ^ {
NSLog(@"%@", [NSThread currentThread]);
};
// 主队列
// dispatch_after(when, dispatch_get_main_queue(), task);
// 全局队列
// dispatch_after(when, dispatch_get_global_queue(0, 0), task);
// 串行队列
dispatch_after(when, dispatch_queue_create("itheima", NULL), task);
NSLog(@"come here");
}
- (void)after {
[self.view performSelector:@selector(setBackgroundColor:) withObject:[UIColor orangeColor] afterDelay:1.0];
NSLog(@"come here");
}
有的时候,在程序开发中,有些代码只想从程序启动就只执行一次,典型的应用场景就是“单例”
// MARK: 一次性执行
- (void)once {
static dispatch_once_t onceToken;
NSLog(@"%ld", onceToken);
dispatch_once(&onceToken, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"一次性吗?");
});
NSLog(@"come here");
}
- (void)demoOnce {
for (int i = 0; i < 10; ++i) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self once];
});
}
}
// 使用 dispatch_once 实现单例
+ (instancetype)sharedSingleton {
static id instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
// 使用互斥锁实现单例
+ (instancetype)sharedSync {
static id syncInstance;
@synchronized(self) {
if (syncInstance == nil) {
syncInstance = [[self alloc] init];
}
}
return syncInstance;
}
面试时只要实现上面
sharedSingleton
方法即可
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
long largeNumber = 1000 * 1000;
// 测试互斥锁
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
for (long i = 0; i < largeNumber; ++i) {
[Singleton sharedSync];
}
NSLog(@"互斥锁: %f", CFAbsoluteTimeGetCurrent() - start);
// 测试 dispatch_once
start = CFAbsoluteTimeGetCurrent();
for (long i = 0; i < largeNumber; ++i) {
[Singleton sharedSingleton];
}
NSLog(@"dispatch_once: %f", CFAbsoluteTimeGetCurrent() - start);
}
- (void)group1 {
// 1. 调度组
dispatch_group_t group = dispatch_group_create();
// 2. 队列
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
// 3. 将任务添加到队列和调度组
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]);
});
// 4. 监听所有任务完成
dispatch_group_notify(group, q, ^{
NSLog(@"OVER %@", [NSThread currentThread]);
});
// 5. 判断异步
NSLog(@"come here");
}
// MARK: - 调度组 2
- (void)group2 {
// 1. 调度组
dispatch_group_t group = dispatch_group_create();
// 2. 队列
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
// dispatch_group_enter & dispatch_group_leave 必须成对出现
dispatch_group_enter(group);
dispatch_group_async(group, q, ^{
NSLog(@"任务 1 %@", [NSThread currentThread]);
// dispatch_group_leave 必须是 block 的最后一句
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_group_async(group, q, ^{
NSLog(@"任务 2 %@", [NSThread currentThread]);
// dispatch_group_leave 必须是 block 的最后一句
dispatch_group_leave(group);
});
// 4. 阻塞式等待调度组中所有任务执行完毕
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
// 5. 判断异步
NSLog(@"OVER %@", [NSThread currentThread]);
}