在上一篇文章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;
}
複製代碼