前言:最近在做SDK方向业扒,對于線程、鎖舒萎、高并發(fā)等關鍵詞使用很頻繁程储。做這個嵌套測試蹭沛,主要是搞懂代碼的執(zhí)行順序,從而對線程章鲤、隊列摊灭、任務有更深的理解。
先上結果
開始測試败徊,默認認為讀者對GCD有所了解
臨界區(qū):gcd的block里的任務帚呼,如果嵌套了gcd,那么其余的作用域皱蹦,我定義為臨界區(qū)煤杀。
一、當前串行隊列
self.cxqueue = dispatch_queue_create("cxqueue", DISPATCH_QUEUE_SERIAL);
1. 在當前隊列追加同步任務沪哺,死鎖
//注意是追加任務 是同一個隊列 這種類型必定死鎖沈自。比如在主線程追加同步任務會死鎖,主線程并不特殊辜妓,就是個串行隊列枯途。
dispatch_async(self.cxqueue, ^{
//不管外邊是async還是sync,內部這樣嵌套的籍滴,必定死鎖
dispatch_sync(self.cxqueue, ^{
});
});
//典型死鎖酪夷,屬于上邊死鎖類型
dispatch_sync(dispatch_get_main_queue(), ^{
});
2. 在當前隊列追加異步任務,先執(zhí)行完臨界區(qū)任務孽惰,再執(zhí)行追加的任務晚岭,不開辟新線程
dispatch_async(self.cxqueue, ^{
NSLog(@"1 任務開始 - %@",[NSThread currentThread]);
dispatch_async(self.cxqueue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"3 - %@",[NSThread currentThread]);
});
dispatch_async(self.cxqueue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"4 - %@",[NSThread currentThread]);
});
NSLog(@"2 任務結尾 - %@",[NSThread currentThread]);
});
打印 3、4會等待臨界區(qū)執(zhí)行完才執(zhí)行
22:56.16 1 任務開始 - <NSThread: >{number = 6, name = (null)}
22:56.16 2 任務結尾 - <NSThread: >{number = 6, name = (null)}
22:56.66 3 - <NSThread: >{number = 6, name = (null)}
22:57.16 4 - <NSThread: >{number = 6, name = (null)}
3. 在當前隊列開啟同步串行隊列灰瞻,臨界區(qū)和同步任務在當前線程順序執(zhí)行腥例,不開辟新線程
dispatch_queue_t queue = dispatch_queue_create("NXqueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(self.cxqueue, ^{
NSLog(@"1 任務開始 - %@",[NSThread currentThread]);
dispatch_sync(queue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"3 同步串行 - %@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
//[NSThread sleepForTimeInterval:0.5];
NSLog(@"4 同步串行 - %@",[NSThread currentThread]);
});
//[NSThread sleepForTimeInterval:1];
NSLog(@"2 任務結尾 - %@",[NSThread currentThread]);
});
打印 臨界區(qū)2會等待3、4執(zhí)行完后才執(zhí)行
43:26.02 1 任務開始 - <NSThread: >{number = 5, name = (null)}
43:26.52 3 同步串行 - <NSThread: >{number = 5, name = (null)}
43:26.53 4 同步串行 - <NSThread: >{number = 5, name = (null)}
43:26.53 2 任務結尾 - <NSThread: >{number = 5, name = (null)}
4. 在當前隊列開啟異步串行隊列酝润,兩者沒有明確的先后順序(異步任務之前的代碼先執(zhí)行燎竖,后邊的誰搶到誰執(zhí)行),新隊列任務按加入順序順序執(zhí)行要销,開啟一個新線程
dispatch_queue_t queue = dispatch_queue_create("NXqueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(self.cxqueue, ^{
NSLog(@"1 任務開始 - %@",[NSThread currentThread]);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"3 異步串行 - %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
//[NSThread sleepForTimeInterval:0.5];
NSLog(@"4 異步串行 - %@",[NSThread currentThread]);
});
//[NSThread sleepForTimeInterval:1];
NSLog(@"2 任務結尾 - %@",[NSThread currentThread]);
});
打印
任務3 會等待 臨界區(qū)1執(zhí)行完
任務4 會等待 任務3執(zhí)行完
臨界區(qū)2任務 不會等待3构回、4執(zhí)行完,但是肯定在1后邊執(zhí)行
40:02.56 1 任務開始 - <NSThread: >{number = 7, name = (null)}
40:02.56 2 任務結尾 - <NSThread: >{number = 7, name = (null)}
40:03.06 3 異步串行 - <NSThread: >{number = 5, name = (null)}
40:03.06 4 異步串行 - <NSThread: >{number = 5, name = (null)}
5. 在當前隊列開啟同步并發(fā)隊列疏咐,臨界區(qū)和同步任務在當前線程順序執(zhí)行纤掸,不開辟新線程
dispatch_queue_t queue = dispatch_queue_create("NXqueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(self.cxqueue, ^{
NSLog(@"1 任務開始 - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:0.5];
dispatch_sync(queue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"3 同步并發(fā) - %@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"4 同步并發(fā) - %@",[NSThread currentThread]);
});
[NSThread sleepForTimeInterval:1];
NSLog(@"2 任務結尾 - %@",[NSThread currentThread]);
});
打印 3等1 4等3 2等4
33:40.64 1 任務開始 - <NSThread: >{number = 6, name = (null)}
33:41.65 3 同步并發(fā) - <NSThread: >{number = 6, name = (null)}
33:42.15 4 同步并發(fā) - <NSThread: >{number = 6, name = (null)}
33:43.16 2 任務結尾 - <NSThread: >{number = 6, name = (null)}
6. 在當前隊列開啟異步并發(fā)隊列,兩者沒有明確的先后順序(異步任務之前的代碼先執(zhí)行浑塞,后邊的誰搶到誰執(zhí)行)借跪,新隊列任務并發(fā)執(zhí)行,開啟多個新線程
dispatch_queue_t queue = dispatch_queue_create("NXqueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(self.cxqueue, ^{
NSLog(@"1 任務開始 - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:0.5];
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"3 異步并發(fā) - %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
//[NSThread sleepForTimeInterval:0.5];
NSLog(@"4 異步并發(fā) - %@",[NSThread currentThread]);
});
//[NSThread sleepForTimeInterval:1];
NSLog(@"2 任務結尾 - %@",[NSThread currentThread]);
});
打印
234均等待1部分執(zhí)行完畢
234互相之間無關聯酌壕,誰先搶到資源誰就調用
把串行隊列想象成主隊列掏愁,就相當于在主線程開了異步并發(fā)隊列
37:42.60 1 任務開始 - <NSThread:>{number = 6, name = (null)}
37:43.11 2 任務結尾 - <NSThread:>{number = 6, name = (null)}
37:43.11 4 異步并發(fā) - <NSThread:>{number = 4, name = (null)}
37:43.61 3 異步并發(fā) - <NSThread:>{number = 7, name = (null)}
二歇由、當前并發(fā)隊列(同步異步結論一樣)
self.bfqueue = dispatch_queue_create("bfqueue", DISPATCH_QUEUE_CONCURRENT);
1. 在當前隊列追加同步任務,臨界區(qū)和同步任務在當前線程順序執(zhí)行果港,不開辟新線程
dispatch_async(self.bfqueue, ^{
NSLog(@"1 任務開始 - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:0.5];
dispatch_sync(self.bfqueue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"3 同步并發(fā) - %@",[NSThread currentThread]);
});
dispatch_sync(self.bfqueue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"4 同步并發(fā) - %@",[NSThread currentThread]);
});
[NSThread sleepForTimeInterval:1];
NSLog(@"2 任務結尾 - %@",[NSThread currentThread]);
});
打印
48:51.16 1 任務開始 - <NSThread:>{number = 7, name = (null)}
48:52.17 3 同步并發(fā) - <NSThread:>{number = 7, name = (null)}
48:52.67 4 同步并發(fā) - <NSThread:>{number = 7, name = (null)}
48:53.67 2 任務結尾 - <NSThread:>{number = 7, name = (null)}
2. 在當前隊列追加異步任務沦泌,任務無序執(zhí)行,開辟多個線程
dispatch_async(self.bfqueue, ^{
NSLog(@"1 任務開始 - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:0.5];
dispatch_async(self.bfqueue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"3 異步并發(fā) - %@",[NSThread currentThread]);
});
dispatch_async(self.bfqueue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"4 異步并發(fā) - %@",[NSThread currentThread]);
});
//[NSThread sleepForTimeInterval:1];
NSLog(@"2 任務結尾 - %@",[NSThread currentThread]);
});
打印 234必定等1部分執(zhí)行完 234無序
52:03.50 1 任務開始 - <NSThread:>{number = 5, name = (null)}
52:04.00 2 任務結尾 - <NSThread:>{number = 5, name = (null)}
52:04.51 4 異步并發(fā) - <NSThread:>{number = 7, name = (null)}
52:04.51 3 異步并發(fā) - <NSThread:>{number = 6, name = (null)}
3. 在當前隊列開啟同步串行隊列辛掠,臨界區(qū)和同步任務在當前線程順序執(zhí)行谢谦,不開辟新線程
dispatch_queue_t queue = dispatch_queue_create("NXqueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(self.bfqueue, ^{
NSLog(@"1 任務開始 - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
dispatch_sync(queue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"3 同步串行 - %@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"4 同步串行 - %@",[NSThread currentThread]);
});
//[NSThread sleepForTimeInterval:1];
NSLog(@"2 任務結尾 - %@",[NSThread currentThread]);
});
打印 順序等待
02:38.89 1 任務開始 - <NSThread:>{number = 6, name = (null)}
02:40.40 3 同步串行 - <NSThread:>{number = 6, name = (null)}
02:40.90 4 同步串行 - <NSThread:>{number = 6, name = (null)}
02:40.90 2 任務結尾 - <NSThread:>{number = 6, name = (null)}
4. 在當前隊列開啟異步串行隊列,兩者沒有明確的先后順序(異步任務之前的代碼先執(zhí)行萝衩,后邊的誰搶到誰執(zhí)行)回挽,新隊列任務按加入順序順序執(zhí)行,開啟一個新線程
dispatch_queue_t queue = dispatch_queue_create("NXqueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(self.bfqueue, ^{
NSLog(@"1 任務開始 - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"3 異步串行 - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:0.5];
});
dispatch_async(queue, ^{
//[NSThread sleepForTimeInterval:0.5];
NSLog(@"4 異步串行 - %@",[NSThread currentThread]);
});
//[NSThread sleepForTimeInterval:1];
NSLog(@"2 任務結尾 - %@",[NSThread currentThread]);
});
打印
234必定等1部分結束
23無序猩谊,4必定等3結束
05:44.06 1 任務開始 - <NSThread:>{number = 6, name = (null)}
05:45.07 2 任務結尾 - <NSThread:>{number = 6, name = (null)}
05:45.57 3 異步串行 - <NSThread:>{number = 4, name = (null)}
05:46.08 4 異步串行 - <NSThread:>{number = 4, name = (null)}
5. 在當前隊列開啟同步并發(fā)隊列厅各,臨界區(qū)和同步任務在當前線程順序執(zhí)行,不開辟新線程
dispatch_queue_t queue = dispatch_queue_create("NXqueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(self.bfqueue, ^{
NSLog(@"1 任務開始 - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
dispatch_sync(queue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"3 同步并發(fā) - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:0.5];
});
dispatch_sync(queue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"4 同步并發(fā) - %@",[NSThread currentThread]);
});
//[NSThread sleepForTimeInterval:1];
NSLog(@"2 任務結尾 - %@",[NSThread currentThread]);
});
打印 3等1 4等3 2等4
11:39.67 1 任務開始 - <NSThread:>{number = 6, name = (null)}
11:41.17 3 同步并發(fā) - <NSThread:>{number = 6, name = (null)}
11:42.18 4 同步并發(fā) - <NSThread:>{number = 6, name = (null)}
11:42.18 2 任務結尾 - <NSThread:>{number = 6, name = (null)}
6. 在當前隊列開啟異步并發(fā)隊列预柒,兩者沒有明確的先后順序(異步任務之前的代碼先執(zhí)行,后邊的誰搶到誰執(zhí)行)袁梗,新隊列任務并發(fā)執(zhí)行宜鸯,開啟多個新線程
dispatch_queue_t queue = dispatch_queue_create("NXqueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(self.bfqueue, ^{
NSLog(@"1 任務開始 - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"3 異步并發(fā) - %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
//[NSThread sleepForTimeInterval:0.5];
NSLog(@"4 異步并發(fā) - %@",[NSThread currentThread]);
});
//[NSThread sleepForTimeInterval:1];
NSLog(@"2 任務結尾 - %@",[NSThread currentThread]);
});
打印
234均等待1部分執(zhí)行完畢
234互相之間無關聯,誰先搶到資源誰就調用
14:12.47 1 任務開始 - <NSThread: >{number = 4, name = (null)}
14:13.47 2 任務結尾 - <NSThread: >{number = 4, name = (null)}
14:13.47 4 異步并發(fā) - <NSThread: >{number = 6, name = (null)}
14:13.97 3 異步并發(fā) - <NSThread: >{number = 7, name = (null)}
結束:建議復制代碼自己跑跑遮怜,干看有點抽象淋袖。demo我就不傳了,就這些東西锯梁,僅供參考即碗,學習。
思考:
- 在什么情況下會遇到數據競爭(data race)問題陌凳;
- 數據競爭怎么解決剥懒;
- 并發(fā)隊列如何串行執(zhí)行;
- 什么時候會用到鎖合敦。