首先要肯定:一個線程只能執行一個任務,執行完纔會執行另外一個任務程序員
先總結一張圖網絡
同步和異步併發
dispatch_sync 是同步的方式執行任務
dispatch_async 是異步的方式執行任務
同步和異步的區別
同步:在當前線程中執行(不會開闢新線程,是在當前線程執行,通常使用同步執行任務會立馬執行,‘寫了跟沒寫同樣’)
異步:在另外一條新的線程中執行(把任務放在主隊列裏,可是不須要立刻執行)異步
串行隊列和並行隊列async
串行隊列:一個一個執行,就算在異步執行的時候,也只會開闢一條新線程(若是主線程是數字是1,那串行隊列只會開闢出一個數字2的線程),而且全部的任務都會在新的線程中執行
dispatch_queue_t queue = dispatch_queue_create(「label」, DISPATCH_QUEUE_SERIAL);
或者
dispatch_queue_t queue = dispatch_queue_create(「label」, NULL); 這兩種的建立方式是同樣的 程序中會常常寫成NULL;spa
並行隊列:在異步執行時會開闢不少新的線程,能夠同時執行多個任務,順序是程序員沒法控制的
dispatch_queue_t queue = dispatch_queue_create(「label」, DISPATCH_QUEUE_CONCURRENT);
併發隊列的同步執行,不開闢新線程,一步一步執行任務
線程
GCD 主線程
1. 專門在主線程上調度任務
2. 不會開闢新線程,無論同步異步執行,只能在主線程上順序執行code
主線程的異步執行任務blog
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self gcdText5]; } - (void)gcdText5 { // 1.得到主線程 dispatch_queue_t queue = dispatch_get_main_queue(); NSLog(@"1-------"); // 2.異步執行任務 // 把任務放在主隊列裏,可是不須要立刻執行 for (int i = 0; i < 10; i++) { NSLog(@"調度前-----"); // 任務:block dispatch_async(queue, ^{ NSLog(@"%@, %d", [NSThread currentThread], i); }); NSLog(@"睡會"); [NSThread sleepForTimeInterval:2.0]; } NSLog(@"完成"); }
這是運行順序是以下圖隊列
2016-05-29 17:09:24.945 GCD[6702:82350] 1------- 2016-05-29 17:09:24.946 GCD[6702:82350] 調度前----- 2016-05-29 17:09:24.946 GCD[6702:82350] 睡會 2016-05-29 17:09:26.951 GCD[6702:82350] 調度前----- 2016-05-29 17:09:26.951 GCD[6702:82350] 睡會 2016-05-29 17:09:28.954 GCD[6702:82350] 調度前----- 2016-05-29 17:09:28.954 GCD[6702:82350] 睡會 2016-05-29 17:09:30.959 GCD[6702:82350] 調度前----- 2016-05-29 17:09:30.959 GCD[6702:82350] 睡會 2016-05-29 17:09:32.963 GCD[6702:82350] 調度前----- 2016-05-29 17:09:32.964 GCD[6702:82350] 睡會 2016-05-29 17:09:34.969 GCD[6702:82350] 調度前----- 2016-05-29 17:09:34.969 GCD[6702:82350] 睡會 2016-05-29 17:09:36.971 GCD[6702:82350] 調度前----- 2016-05-29 17:09:36.971 GCD[6702:82350] 睡會 2016-05-29 17:09:38.971 GCD[6702:82350] 調度前----- 2016-05-29 17:09:38.971 GCD[6702:82350] 睡會 2016-05-29 17:09:40.974 GCD[6702:82350] 調度前----- 2016-05-29 17:09:40.974 GCD[6702:82350] 睡會 2016-05-29 17:09:42.977 GCD[6702:82350] 調度前----- 2016-05-29 17:09:42.977 GCD[6702:82350] 睡會 2016-05-29 17:09:44.981 GCD[6702:82350] 完成 2016-05-29 17:09:44.981 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 0 2016-05-29 17:09:44.982 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 1 2016-05-29 17:09:44.982 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 2 2016-05-29 17:09:44.982 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 3 2016-05-29 17:09:44.982 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 4 2016-05-29 17:09:44.982 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 5 2016-05-29 17:09:44.983 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 6 2016-05-29 17:09:44.983 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 7 2016-05-29 17:09:44.983 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 8 2016-05-29 17:09:44.983 GCD[6702:82350] <NSThread: 0x7ffddb501290>{number = 1, name = main}, 9
爲何會產生這種效果呢
由於異步執行只是把任務放在隊列中,不會立刻執行,由於主隊列的特殊性又不能開闢新的線程,因此會等到主線程的任務執行完纔會執行隊列中的任務 , 如圖
此時主線程正在執行gcdText5這個任務,
當gocText5任務執行完成後在執行 綠色的0,1任務
主線程的同步執行任務
只須要將代碼
dispatch_async
換成
dispatch_sync
就能夠了,這是運行效果回事這樣的
這是由於
同步任務要立刻執行,可是線程沒空,線程正在執行gcdText5,須要等gcdText5執行完,可是gcdText5在等這個同步任務執行結束,因此會形成主線程阻塞,產生死鎖
全局隊列
全局隊列和併發隊列的區別
1.全局隊列沒有名稱,併發隊列有名稱
2.全局隊列,是供全部的應用程序共享
3.在MRC開發中併發隊列須要釋放,全局隊列不須要管理
// 全局隊列:是蘋果官方提供的,是指上也是併發隊列 /* 參數:第一個參數,通常寫 0 (能夠適配iOS 7 & 8) (優先級)DISPATCH_QUEUE_PRIORITY_HIGH: QOS_CLASS_USER_INITIATED (0) DISPATCH_QUEUE_PRIORITY_DEFAULT: QOS_CLASS_DEFAULT DISPATCH_QUEUE_PRIORITY_LOW: QOS_CLASS_UTILITY DISPATCH_QUEUE_PRIORITY_BACKGROUND: QOS_CLASS_BACKGROUND 第二個參數:保留參數 0 **/ dispatch_queue_t queue = dispatch_get_global_queue(0, 0); for (int i = 0; i < 10; i ++) { dispatch_async(queue, ^{ NSLog(@"%@, %d", [NSThread currentThread], i); }); }
調度組
/* 應用場景 開發的時候出現多個網絡請求(每個網絡請求的時間長短不必定),都完成之後,在統一通知用戶 例如:下載小說:三國演義 西遊記 金x梅 **/ // 實例化一個調度組 dispatch_group_t group = dispatch_group_create(); // 隊列 dispatch_queue_t queue = dispatch_get_global_queue(0, 0); // 任務添加到隊列 dispatch_group_async(group, queue, ^{ NSLog(@"下載小說A%@", [NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ NSLog(@"下載小說b%@", [NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ NSLog(@"下載小說x%@", [NSThread currentThread]); }); // 得到全部調度組裏面的異步任務完成的通知(能夠跨隊列通訊) dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // 在主線程更新UI NSLog(@"下載完成,請觀看%@", [NSThread currentThread]); });
一次性執行
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self once]; } #pragma mark - 一次性執行 - (void)once { static dispatch_once_t onceToken; NSLog(@"%ld", onceToken); dispatch_once(&onceToken, ^{ NSLog(@"%ld", onceToken); NSLog(@"真的只會執行一次麼?"); }); NSLog(@"完成"); }
運行結果
2016-05-30 17:34:57.939 GCD[29725:464402] 0 2016-05-30 17:34:57.940 GCD[29725:464402] 140734769974144 2016-05-30 17:34:57.940 GCD[29725:464402] 真的只會執行一次麼? 2016-05-30 17:34:57.940 GCD[29725:464402] 完成 2016-05-30 17:34:59.898 GCD[29725:464402] -1 2016-05-30 17:34:59.898 GCD[29725:464402] 完成 2016-05-30 17:35:00.690 GCD[29725:464402] -1 2016-05-30 17:35:00.690 GCD[29725:464402] 完成 2016-05-30 17:35:01.090 GCD[29725:464402] -1 2016-05-30 17:35:01.091 GCD[29725:464402] 完成 2016-05-30 17:35:02.146 GCD[29725:464402] -1 2016-05-30 17:35:02.147 GCD[29725:464402] 完成