在上一篇文章iOS多线程开发—GCD(二)中我介绍了什么是多线程,GCD与线程的关系,以及如何建立队列和简单的使用,在这篇文章中我讲重点总结一下GCD一些高级用法。编程
咱们能够经过dispatch_get_global_queue(long identifier, unsigned long flags);获取全局队列,经过dispatch_get_main_queue();获取主队列,经过dispatch_queue_create(const char *_Nullable label,dispatch_queue_attr_t _Nullable attr);建立并行或者串行队列。 咱们须要注意的是,dispatch_get_global_queue(long identifier, unsigned long flags);dispatch_get_main_queue();这两种方法都是让咱们获取系统已经建立好的队列,所以咱们不须要对这些队列进行内存管理,系统会帮助咱们在合适的时间释放这些队列。安全
dispatch_queue_create(const char *_Nullable label,dispatch_queue_attr_t _Nullable attr); 这个方法可让咱们建立一个队列,第一个参数是队列的名字,也能够为空,可是不利于debug。第二个参数是队列的类型,若是写NULL,那么默认是串行队列,DISPATCH_QUEUE_CONCURRENT将建立并行队列。bash
//串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("com.jiaxiang.serialQueue", DISPATCH_QUEUE_SERIAL);
//并行队列
dispatch_queue_t concurrentQueue1 = dispatch_queue_create("com.jiaxiang.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
复制代码
理论上咱们能够在这里建立任意多个队列,而且多个串行队列是能够并行执行的。可是当咱们使用了过多的串行队列时,咱们会建立相应的串行线程,过多的线程建立将消耗系统资源。多线程
//获取主队列,在主线程上执行
dispatch_queue_t mainQueue = dispatch_get_main_queue();
//获取默认优先级的全局队列,并行执行
dispatch_queue_t concurrentQueue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
复制代码
dispatch_get_global_queue(long identifier, unsigned long flags);第一个参数指定队列的优先级,第二个参数是flag,大多时间使用0。 优先级分为四级,从高到低依次为,高,默认,低,后台app
#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 mainQueue = dispatch_get_main_queue();
dispatch_queue_t serialQueue = dispatch_queue_create("com.jiaxiang.serialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(concurrentQueue1, ^{
//同步任务追加到并行队列中
NSLog(@"Concurrent Queue");
NSLog(@"Concurrent Queue%@",[NSThread currentThread]);
dispatch_async(mainQueue, ^{
//异步任务追加到主队列中
NSLog(@"Main Queue");
NSLog(@"Main Queue%@",[NSThread currentThread]);
});
});
NSLog(@"Done");
NSLog(@"Done%@",[NSThread currentThread]);
复制代码
上面这个使用,让咱们能够把耗时操做放到并行队列中,而且将结果放到主队列中执行。异步
dispatch_set_target_queue(dispatch_object_t object,dispatch_queue_t _Nullable queue);这个方法让咱们将一个队列的执行优先级设置为另外一个队列的优先级。第一个参数是变动优先级的队列,第二个参数是目标优先级队列。第一个参数不能是系统提供的Main Queue 和 Global Dispatch Queue。async
//将serialQueue的优先级设置为与concurrentQueue2相同
dispatch_queue_t serialQueue = dispatch_queue_create("com.jiaxiang.serialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t concurrentQueue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_set_target_queue(serialQueue, concurrentQueue2);
复制代码
dispatch_queue_t serialQueue1 = dispatch_queue_create("com.jiaxiang.serialQueue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue2 = dispatch_queue_create("com.jiaxiang.serialQueue2", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue3 = dispatch_queue_create("com.jiaxiang.serialQueue2", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue4 = dispatch_queue_create("com.jiaxiang.serialQueue3", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"0");
});
dispatch_async(serialQueue1, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"1");
});
dispatch_async(serialQueue2, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"2");
});
dispatch_async(serialQueue3, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"3");
});
dispatch_async(serialQueue4, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"4");
});
复制代码
以上建立的五个串行队列在执行的时候是并行执行的,它们每次执行的前后顺序并不固定。可是当咱们使用dispatch_set_target以后它们将变成串行执行。ide
dispatch_queue_t serialQueue1 = dispatch_queue_create("com.jiaxiang.serialQueue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue2 = dispatch_queue_create("com.jiaxiang.serialQueue2", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue3 = dispatch_queue_create("com.jiaxiang.serialQueue2", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue4 = dispatch_queue_create("com.jiaxiang.serialQueue3", DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(serialQueue1, serialQueue);
dispatch_set_target_queue(serialQueue2, serialQueue);
dispatch_set_target_queue(serialQueue3, serialQueue);
dispatch_set_target_queue(serialQueue4, serialQueue);
dispatch_async(serialQueue, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"0");
});
dispatch_async(serialQueue1, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"1");
});
dispatch_async(serialQueue2, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"2");
});
dispatch_async(serialQueue3, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"3");
});
dispatch_async(serialQueue4, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"4");
});
复制代码
dispatch_after(dispatch_time_t when,dispatch_queue_t queue, dispatch_block_t block);第一个参数指定多长时间之后将任务追加到指定的队列,第二个参数指定执行任务的队列,第三个参数是追加的任务。须要清楚的是任务并非在指定的时间以后执行,而是任务在指定的时间后被追加到队列,所以任务执行的时间极可能在指定的时间以后。而且这个方法执行的是异步任务,所以当指定的队列是main queue的时候也不用担忧死锁。函数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"Hello");
});
NSLog(@"Done After");
复制代码
在使用GCD的时候,咱们有时候会但愿当咱们执行完并行队列以后,可以追加一个任务在全部并行队列中的任务执行完以后再执行。这时候咱们就可使用dispatch group来实现这个需求。post
dispatch_queue_t concurrentQueue1 = dispatch_queue_create("com.jiaxiang.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, concurrentQueue1, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"1");
});
dispatch_group_async(group, concurrentQueue1, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"2");
});
dispatch_group_async(group, concurrentQueue1, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"3");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"Done");
});
复制代码
+ (void)withGroup:(dispatch_group_t)group
sendAsynchronousRequest:(NSURLRequest *)request
queue:(NSOperationQueue *)queue
completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler
{
if (group == NULL) {
[self sendAsynchronousRequest:request
queue:queue
completionHandler:handler];
} else {
dispatch_group_enter(group);
[self sendAsynchronousRequest:request
queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
handler(response, data, error);
dispatch_group_leave(group);
}];
}
}
复制代码
当咱们须要让并行队列中的1,2,3这几个任务执行完以后,执行任务4,而后再执行任务5,6,7以此避免在在写入数据的同同时读取数据,形成数据竞争,这时候咱们可使用dispatch_barrier_async。
self.serialQueue = dispatch_queue_create("com.serialQueue.com", 0);
- (void)setCount:(NSUInteger)count forKey:(NSString *)key
{
key = [key copy];
dispatch_async(self.serialQueue, ^(){
if (count == 0) {
[self.counts removeObjectForKey:key];
} else {
self.counts[key] = @(count);
}
});
}
- (NSUInteger)countForKey:(NSString *)key;
{
__block NSUInteger count;
dispatch_sync(self.serialQueue, ^(){
NSNumber *n = self.counts[key];
count = [n unsignedIntegerValue];
});
return count;
}
复制代码
self.concurrentQueue = dispatch_queue_creat("com.concurrentQueue.jiaxiang",DISPATCH_QUEUE_CONCURRENT);
- (void)setCount:(NSUInteger)count forKey:(NSString *)key
{
key = [key copy];
dispatch_barrier_async(self.isolationQueue, ^(){
if (count == 0) {
[self.counts removeObjectForKey:key];
} else {
self.counts[key] = @(count);
}
});
}
复制代码
dispatch_queue_t concurrentQueue1 = dispatch_queue_create("com.jiaxiang.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue1, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"1");
});
dispatch_async(concurrentQueue1, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"2");
});
dispatch_async(concurrentQueue1, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"3");
});
dispatch_barrier_async(concurrentQueue1, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"4");
});
dispatch_async(concurrentQueue1, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"5");
});
dispatch_async(concurrentQueue1, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"6");
});
dispatch_async(concurrentQueue1, ^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"7");
});
复制代码
该函数按指定的次数将指定的任务追加到队列中,并等待所有处理执行结束。
dispatch_queue_t concurrentQueue1 = dispatch_queue_create("com.jiaxiang.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(10, concurrentQueue1, ^(size_t index) {
NSLog(@"%zu",index);
});
NSLog(@"Done");
复制代码
dispatch_suspend(queue),挂起指定的队列,队列中已经执行的任务无影响,为执行的任务中止执行。 dispatch_resume(queue),恢复指定的队列,队列中为执行的任务继续执行。
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block int j = 0;
dispatch_async(queue, ^{
j = 100;
dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"finish j = %zd", j);
复制代码
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
for (int i = 0; i < 100; i++) {
dispatch_async(queue, ^{
// 至关于加锁
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"i = %zd semaphore = %@", i, semaphore);
// 至关于解锁
dispatch_semaphore_signal(semaphore);
});
}
复制代码
dispathc_once函数能够确保某个block在应用程序执行的过程当中只被处理一次,并且它是线程安全的。
+ (Manager *)sharedInstance {
static Manager *sharedManagerInstance = nil;
static dispatch_once_t once;
dispatch_once($once, ^{
sharedManagerInstance = [[Manager alloc] init];
});
return sharedManagerInstance;
}
复制代码