1. GCD 的兩個(gè)核心 :任務(wù) 和 隊(duì)列
任務(wù):就是執(zhí)行操作的意思脖捻,換句話(huà)說(shuō)就是你在線程中執(zhí)行的那段代碼佩耳。在 GCD 中是放在 block 中的享言。執(zhí)行任務(wù)有兩種方式:同步執(zhí)行(sync)和異步執(zhí)行(async)。兩者的主要區(qū)別是:是否等待隊(duì)列的任務(wù)執(zhí)行結(jié)束,以及是否具備開(kāi)啟新線程的能力册着。
-
同步執(zhí)行(sync):
- 同步添加任務(wù)到指定的隊(duì)列中,在添加的任務(wù)執(zhí)行結(jié)束之前脾歧,會(huì)一直等待甲捏,直到隊(duì)列里面的任務(wù)完成之后再繼續(xù)執(zhí)行。
- 只能在當(dāng)前線程中執(zhí)行任務(wù)鞭执,不具備開(kāi)啟新線程的能力司顿。
-
異步執(zhí)行(async):
- 異步添加任務(wù)到指定的隊(duì)列中,它不會(huì)做任何等待兄纺,可以繼續(xù)執(zhí)行任務(wù)大溜。
可以在新的線程中執(zhí)行任務(wù),具備開(kāi)啟新線程的能力估脆。
- 異步添加任務(wù)到指定的隊(duì)列中,它不會(huì)做任何等待兄纺,可以繼續(xù)執(zhí)行任務(wù)大溜。
隊(duì)列(Dispatch Queue):這里的隊(duì)列指執(zhí)行任務(wù)的等待隊(duì)列钦奋,即用來(lái)存放任務(wù)的隊(duì)列。隊(duì)列是一種特殊的線性表,采用 FIFO(先進(jìn)先出)的原則付材,即新任務(wù)總是被插入到隊(duì)列的末尾朦拖,而讀取任務(wù)的時(shí)候總是從隊(duì)列的頭部開(kāi)始讀取。每讀取一個(gè)任務(wù)厌衔,則從隊(duì)列中釋放一個(gè)任務(wù)璧帝。
- 串行隊(duì)列(Serial Dispatch Queue):每次只有一個(gè)任務(wù)被執(zhí)行。讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行富寿。只開(kāi)啟一個(gè)線程睬隶,一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù)
- 并行隊(duì)列(Concurrent Dispatch Queue):可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行页徐。可以開(kāi)啟多個(gè)線程理疙,并且同時(shí)執(zhí)行任務(wù)
個(gè)人理解: 隊(duì)列(Serial和Concurrent) 決定是否 具備 開(kāi)啟線程的能力,sync和async決定是否 開(kāi)啟 另外的線程
開(kāi)啟線程的能力跟所在的線程沒(méi)關(guān)系
2. 代碼解析
代碼1
//創(chuàng)建串行隊(duì)列
dispatch_queue_t mySerialQueue = dispatch_queue_create("my_test_queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t myQueue = dispatch_queue_create("my_test_queue_2", DISPATCH_QUEUE_SERIAL);
//異步執(zhí)行+串行隊(duì)列:開(kāi)啟一個(gè)線程
dispatch_async(mySerialQueue, ^{
//任務(wù)1
NSLog(@"7-----%@",[NSThread currentThread]);
NSLog(@"7 === start");
//異步 不用等待 繼續(xù)執(zhí)行
dispatch_async(myQueue, ^{
//任務(wù)3
NSLog(@"4 === start");
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"4-----%@",[NSThread currentThread]);
}
dispatch_async(mySerialQueue, ^{
//任務(wù)4
NSLog(@"8 === start");
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"8-----%@",[NSThread currentThread]);
}
NSLog(@"8 === end");
});
NSLog(@"4 === end");
});
//異步 不用等待繼續(xù)執(zhí)行
dispatch_async(myQueue, ^{
//任務(wù)5
NSLog(@"5 === start");
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"5-----%@",[NSThread currentThread]);
}
});
NSLog(@"7 === end");
});
//串行隊(duì)列 需一個(gè)一個(gè)執(zhí)行 :等待 NSLog(@"7 === end") 執(zhí)行后再執(zhí)行
dispatch_async(mySerialQueue, ^{
//任務(wù)2
NSLog(@"9 === start");
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"9-----%@",[NSThread currentThread]);
}
NSLog(@"9 === end");
});
執(zhí)行后輸出結(jié)果是 :
2019-04-16 14:37:09.149808+0800 test123[95964:8582595] 7-----<NSThread: 0x6000020ea7c0>{number = 3, name = (null)}
2019-04-16 14:37:09.149973+0800 test123[95964:8582595] 7 === start
2019-04-16 14:37:09.150092+0800 test123[95964:8582595] 7 === end
2019-04-16 14:37:09.150102+0800 test123[95964:8582592] 4 === start
2019-04-16 14:37:09.150225+0800 test123[95964:8582595] 9 === start
2019-04-16 14:37:11.153315+0800 test123[95964:8582595] 9-----<NSThread: 0x6000020ea7c0>{number = 3, name = (null)}
2019-04-16 14:37:11.153338+0800 test123[95964:8582592] 4-----<NSThread: 0x6000020e3040>{number = 4, name = (null)}
2019-04-16 14:37:13.157628+0800 test123[95964:8582595] 9-----<NSThread: 0x6000020ea7c0>{number = 3, name = (null)}
2019-04-16 14:37:13.157649+0800 test123[95964:8582592] 4-----<NSThread: 0x6000020e3040>{number = 4, name = (null)}
2019-04-16 14:37:13.158006+0800 test123[95964:8582595] 9 === end
2019-04-16 14:37:13.158021+0800 test123[95964:8582592] 4 === end
2019-04-16 14:37:13.158315+0800 test123[95964:8582592] 5 === start
2019-04-16 14:37:13.158366+0800 test123[95964:8582595] 8 === start
2019-04-16 14:37:15.163083+0800 test123[95964:8582592] 5-----<NSThread: 0x6000020e3040>{number = 4, name = (null)}
2019-04-16 14:37:15.163111+0800 test123[95964:8582595] 8-----<NSThread: 0x6000020ea7c0>{number = 3, name = (null)}
2019-04-16 14:37:17.163967+0800 test123[95964:8582592] 5-----<NSThread: 0x6000020e3040>{number = 4, name = (null)}
2019-04-16 14:37:17.163967+0800 test123[95964:8582595] 8-----<NSThread: 0x6000020ea7c0>{number = 3, name = (null)}
2019-04-16 14:37:17.164365+0800 test123[95964:8582595] 8 === end
分析:任務(wù)3(4===start) 比 任務(wù)2(9===start) 早輸出原因:異步執(zhí)行 任務(wù)3 后泞坦,下邊代碼還有耗時(shí)操作(任務(wù)5窖贤、NSLog)所以 任務(wù)2 需要等待,會(huì)先異步執(zhí)行 任務(wù)3(4 === start )
代碼2
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"1 === start");
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"1-----%@",[NSThread currentThread]);
}
NSLog(@"1 === end");
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"2 === start");
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"2-----%@",[NSThread currentThread]);
}
NSLog(@"2 === end");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
//創(chuàng)建串行隊(duì)列
dispatch_queue_t mySerialQueue = dispatch_queue_create("my_test_queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t myQueue = dispatch_queue_create("my_test_queue_2", DISPATCH_QUEUE_SERIAL);
//異步執(zhí)行+串行隊(duì)列:開(kāi)啟一個(gè)線程
dispatch_async(mySerialQueue, ^{
NSLog(@"7-----%@",[NSThread currentThread]);
NSLog(@"7 === start");
//異步 不用等待 繼續(xù)執(zhí)行
dispatch_async(myQueue, ^{
NSLog(@"4 === start");
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"4-----%@",[NSThread currentThread]);
}
dispatch_async(mySerialQueue, ^{
NSLog(@"8 === start");
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"8-----%@",[NSThread currentThread]);
}
NSLog(@"8 === end");
});
NSLog(@"4 === end");
});
//異步 不用等待繼續(xù)執(zhí)行
dispatch_async(myQueue, ^{
NSLog(@"5 === start");
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"5-----%@",[NSThread currentThread]);
}
});
NSLog(@"7 === end");
});
//串行隊(duì)列 需一個(gè)一個(gè)執(zhí)行 :等待 NSLog(@"7 === end") 執(zhí)行后再執(zhí)行
dispatch_async(mySerialQueue, ^{
NSLog(@"9 === start");
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"9-----%@",[NSThread currentThread]);
}
NSLog(@"9 === end");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"3 === start");
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"3-----%@",[NSThread currentThread]);
}
});
輸出結(jié)果:
2019-04-16 14:49:41.670736+0800 test123[96172:8588712] 7-----<NSThread: 0x600003583cc0>{number = 3, name = (null)}
2019-04-16 14:49:41.670807+0800 test123[96172:8588710] 1 === start
2019-04-16 14:49:41.670865+0800 test123[96172:8588711] 2 === start
2019-04-16 14:49:41.670975+0800 test123[96172:8588712] 7 === start
2019-04-16 14:49:41.671074+0800 test123[96172:8588712] 7 === end
2019-04-16 14:49:41.671086+0800 test123[96172:8588709] 4 === start
2019-04-16 14:49:41.671177+0800 test123[96172:8588712] 9 === start
2019-04-16 14:49:43.675862+0800 test123[96172:8588710] 1-----<NSThread: 0x600003597380>{number = 4, name = (null)}
2019-04-16 14:49:43.675871+0800 test123[96172:8588712] 9-----<NSThread: 0x600003583cc0>{number = 3, name = (null)}
2019-04-16 14:49:43.675862+0800 test123[96172:8588711] 2-----<NSThread: 0x60000358af40>{number = 5, name = (null)}
2019-04-16 14:49:43.675864+0800 test123[96172:8588709] 4-----<NSThread: 0x60000358adc0>{number = 6, name = (null)}
2019-04-16 14:49:45.680467+0800 test123[96172:8588711] 2-----<NSThread: 0x60000358af40>{number = 5, name = (null)}
2019-04-16 14:49:45.680547+0800 test123[96172:8588712] 9-----<NSThread: 0x600003583cc0>{number = 3, name = (null)}
2019-04-16 14:49:45.680467+0800 test123[96172:8588710] 1-----<NSThread: 0x600003597380>{number = 4, name = (null)}
2019-04-16 14:49:45.680478+0800 test123[96172:8588709] 4-----<NSThread: 0x60000358adc0>{number = 6, name = (null)}
2019-04-16 14:49:45.680875+0800 test123[96172:8588711] 2 === end
2019-04-16 14:49:45.680874+0800 test123[96172:8588712] 9 === end
2019-04-16 14:49:45.680967+0800 test123[96172:8588709] 4 === end
2019-04-16 14:49:45.680874+0800 test123[96172:8588710] 1 === end
2019-04-16 14:49:45.681135+0800 test123[96172:8588712] 8 === start
2019-04-16 14:49:45.681224+0800 test123[96172:8588709] 5 === start
2019-04-16 14:49:45.681723+0800 test123[96172:8588662] 3 === start
2019-04-16 14:49:47.682394+0800 test123[96172:8588662] 3-----<NSThread: 0x6000035e2940>{number = 1, name = main}
2019-04-16 14:49:47.683973+0800 test123[96172:8588709] 5-----<NSThread: 0x60000358adc0>{number = 6, name = (null)}
2019-04-16 14:49:47.684043+0800 test123[96172:8588712] 8-----<NSThread: 0x600003583cc0>{number = 3, name = (null)}
2019-04-16 14:49:49.683874+0800 test123[96172:8588662] 3-----<NSThread: 0x6000035e2940>{number = 1, name = main}
2019-04-16 14:49:49.684750+0800 test123[96172:8588709] 5-----<NSThread: 0x60000358adc0>{number = 6, name = (null)}
2019-04-16 14:49:49.684799+0800 test123[96172:8588712] 8-----<NSThread: 0x600003583cc0>{number = 3, name = (null)}
2019-04-16 14:49:49.685113+0800 test123[96172:8588712] 8 === end
解析:1和2先后順序不一定 1贰锁、2赃梧、4、9相互交替執(zhí)行豌熄,5肯定在4結(jié)束后執(zhí)行授嘀,8肯定在9執(zhí)行完后執(zhí)行,最后5和8交替執(zhí)行