1.多線程中的的一些基本概念
進程:對于操作系統(tǒng)來說,一個可以運行的應(yīng)用程序(app)就是一個進程换衬。
線程:一個app中可能會同時處理不同的任務(wù)痰驱,比如請求數(shù)據(jù)和頁面刷新,請求數(shù)據(jù)會在子線程處理瞳浦,頁面刷新會在主線程處理担映,一個程序中可以有多個線程。
隊列:在GCD中的隊列就是指用來存放任務(wù)的等待隊列叫潦,把任務(wù)添加到隊列后蝇完,我們不需要跟線程打交道。GCD在后段管理著一個線程池矗蕊。
隊列可以分為串行隊列和并發(fā)隊列短蜕。
串行隊列:在這個隊列中的任務(wù)會按照FIFO一個一個執(zhí)行,只會開啟一個線程傻咖。
并發(fā)隊列:這個隊列中的任務(wù)會按照FIFO出來朋魔,但是會同時開辟多個線程執(zhí)行。
主隊列:是一個全局可用的串行隊列卿操。
全局隊列:一個全局可用的并發(fā)隊列警检。
同步執(zhí)行(dispatch_sync):同步執(zhí)行就是指使用 dispatch_sync方法將任務(wù)同步的添加到隊列里,在添加的任務(wù)執(zhí)行結(jié)束之前硬纤,當前線程會被阻塞解滓,然后會一直等待,直到任務(wù)完成筝家。
dispatch_sync添加的任務(wù)只能在當前線程執(zhí)行洼裤,不具備開啟新線程的能力
異步執(zhí)行(dispatch_async):異步執(zhí)行就是指使用dispatch_async方法將任務(wù)異步的添加到隊列里,它不需要等待任務(wù)執(zhí)行結(jié)束溪王,不需要做任何等待就能繼續(xù)執(zhí)行任務(wù)
dispatch_async添加的任務(wù)可以在新的線程中執(zhí)行任務(wù)腮鞍,具備開啟新線程的能力,但并不一定會開啟新線程
2.不同隊列對應(yīng)同步異步執(zhí)行的情況
2.1 同步執(zhí)行主隊列中的任務(wù)
2.1.1在主線程中同步執(zhí)行主隊列的任務(wù)
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"在主線程同步添加主隊列任務(wù)");
});
運行結(jié)果卡死莹菱,GCD-主線程上同步執(zhí)行主隊列任務(wù)卡死
2.1.2在子線程中同步執(zhí)行主隊列任務(wù)
NSLog(@"進入子線程之前,當前線程:%@", [NSThread currentThread]);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"進入子線程,當前線程:%@", [NSThread currentThread]);
for (int i = 0; i < 10; i++) {
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"在子線程中開啟的主隊列同步任務(wù)i=%d,當前線程:%@", i, [NSThread currentThread]);
});
}
NSLog(@"子線程中的主隊列任務(wù)已經(jīng)完成,當前線程:%@", [NSThread currentThread]);
});
NSLog(@"子線程代碼已經(jīng)結(jié)束,當前線程:%@", [NSThread currentThread]);
運行結(jié)果:主隊列中的任務(wù)在主線程按順序執(zhí)行移国。主隊列中的任務(wù)等主線程執(zhí)行完再執(zhí)行。
2.2異步執(zhí)行主隊列的任務(wù)
2.2.1在主線程中異步執(zhí)行主隊列的任務(wù)
NSLog(@"主隊列任務(wù)添加前");
for (int i = 0; i < 10; i++) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"在子線程中開啟的主隊列異步任務(wù)i=%d,當前線程:%@", i, [NSThread currentThread]);
});
}
NSLog(@"主隊列任務(wù)添加后");
運行結(jié)果:
主隊列任務(wù)添加前
主隊列任務(wù)添加后
在子線程中開啟的主隊列異步任務(wù)i=0,當前線程:<NSThread: 0x600000795480>{number = 1, name = main}
在子線程中開啟的主隊列異步任務(wù)i=1,當前線程:<NSThread: 0x600000795480>{number = 1, name = main}
······
在子線程中開啟的主隊列異步任務(wù)i=9,當前線程:<NSThread: 0x600000795480>{number = 1, name = main}
先執(zhí)行主隊列之外主線程中的代碼道伟,然后按順序在主線程執(zhí)行主隊列中的任務(wù)迹缀。
2.2.2在子線程中異步執(zhí)行主隊列的任務(wù)
NSLog(@"進入子線程之前,當前線程:%@", [NSThread currentThread]);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"進入子線程,當前線程:%@", [NSThread currentThread]);
for (int i = 0; i < 10; i++) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"在子線程中開啟的主隊列異步任務(wù)i=%d,當前線程:%@", i, [NSThread currentThread]);
});
}
NSLog(@"子線程中的主隊列任務(wù)已經(jīng)完成,當前線程:%@", [NSThread currentThread]);
});
NSLog(@"子線程代碼已經(jīng)結(jié)束,當前線程:%@", [NSThread currentThread]);
運行結(jié)果:先執(zhí)行主隊列之外主線程中的代碼使碾,然后按順序在主線程執(zhí)行主隊列中的任務(wù)。
2.3串行隊列同步執(zhí)行
dispatch_queue_t queue = dispatch_queue_create("testSerialSync", DISPATCH_QUEUE_SERIAL);
NSLog(@"當前線程為%@", [NSThread currentThread]);
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@"i = %d,當前線程為%@", i, [NSThread currentThread]);
});
}
for (int j = 0; j < 10; j++) {
NSLog(@"j = %d, 當前線程為%@", j, [NSThread currentThread]);
}
結(jié)果: 不開辟子線程祝懂,在主線程按順序執(zhí)行票摇。主線程中的代碼會等串行隊列中的任務(wù)結(jié)束后在執(zhí)行。
2.4串行隊列異步執(zhí)行
dispatch_queue_t queue = dispatch_queue_create("testSerialSync", DISPATCH_QUEUE_SERIAL);
NSLog(@"當前線程為%@", [NSThread currentThread]);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"i = %d,當前線程為%@", i, [NSThread currentThread]);
});
}
for (int j = 0; j < 10; j++) {
NSLog(@"j = %d, 當前線程為%@", j, [NSThread currentThread]);
}
結(jié)果:開辟一個子線程砚蓬,同步隊列中的任務(wù)在子線程按順序執(zhí)行矢门。主線程的代碼會和串行隊列中的任務(wù)同時執(zhí)行。
2.5并發(fā)隊列同步執(zhí)行
dispatch_queue_t queue = dispatch_queue_create("testSerialSync", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"當前線程為%@", [NSThread currentThread]);
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@"i = %d,當前線程為%@", i, [NSThread currentThread]);
});
}
for (int j = 0; j < 10; j++) {
NSLog(@"j = %d, 當前線程為%@", j, [NSThread currentThread]);
}
結(jié)果:不開辟子線程灰蛙,在主線程中按順序執(zhí)行祟剔,主線程中的任務(wù)等并發(fā)隊列中的任務(wù)執(zhí)行完再執(zhí)行。
2.6并發(fā)隊列異步執(zhí)行
dispatch_queue_t queue = dispatch_queue_create("testSerialSync", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"當前線程為%@", [NSThread currentThread]);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"i = %d,當前線程為%@", i, [NSThread currentThread]);
});
}
NSLog(@"當前線程為%@", [NSThread currentThread]);
結(jié)果:開辟多個線程摩梧,和主線程之后的代碼同時執(zhí)行物延,主線程按順序執(zhí)行。
總結(jié):
在主線程中同步執(zhí)行主隊列的任務(wù): 卡死
在子線程中同步執(zhí)行主隊列任務(wù): 主隊列中的任務(wù)在主線程按順序執(zhí)行障本。主隊列中的任務(wù)等主線程之后的代碼執(zhí)行完再執(zhí)行教届。
在主線程中異步執(zhí)行主隊列的任務(wù): 先執(zhí)行主隊列之外主線程中的代碼,然后按順序在主線程執(zhí)行主隊列中的任務(wù)驾霜。
在子線程中異步執(zhí)行主隊列的任務(wù): 先執(zhí)行主隊列之外主線程中的代碼,然后按順序在主線程執(zhí)行主隊列中的任務(wù)买置。
串行隊列同步執(zhí)行:不開辟子線程粪糙,在主線程按順序執(zhí)行。主線程中的代碼會等串行隊列中的任務(wù)結(jié)束后在執(zhí)行忿项。
串行隊列異步執(zhí)行:開辟一個子線程蓉冈,同步隊列中的任務(wù)在子線程按順序執(zhí)行。主線程的代碼會和串行隊列中的任務(wù)同時執(zhí)行轩触。
并發(fā)隊列同步執(zhí)行:不開辟子線程寞酿,在主線程中按順序執(zhí)行,主線程中的任務(wù)等并發(fā)隊列中的任務(wù)執(zhí)行完再執(zhí)行脱柱。
并發(fā)隊列異步執(zhí)行:開辟多個線程伐弹,和主線程之后的代碼同時執(zhí)行,主線程按順序執(zhí)行榨为。
3.隊列的掛起和恢復(fù)
掛起指定隊列:dispatch_suspend(queue);
恢復(fù)指定隊列:dispatchp_resume(queue);
示例:
dispatch_queue_t queue = dispatch_queue_create("queueSuspend", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"隊列沒有掛起前添加的任務(wù)開始執(zhí)行");
sleep(3);
NSLog(@"隊列沒有掛起前添加的任務(wù)執(zhí)行結(jié)束");
});
NSLog(@"隊列還沒有掛起");
dispatch_suspend(queue);
NSLog(@"隊列已經(jīng)掛起");
dispatch_async(queue, ^{
NSLog(@"隊列被掛起之后添加的任務(wù)開始執(zhí)行");
});
NSLog(@"5秒后恢復(fù)隊列");
sleep(5);
dispatch_resume(queue);
NSLog(@"隊列已經(jīng)恢復(fù)");
打印結(jié)果:
2020-02-28 15:52:12.132254+0800 Test[23449:1607212] 隊列還沒有掛起
2020-02-28 15:52:12.132259+0800 Test[23449:1607343] 隊列沒有掛起前添加的任務(wù)開始執(zhí)行
2020-02-28 15:52:12.132424+0800 Test[23449:1607212] 隊列已經(jīng)掛起
2020-02-28 15:52:12.132525+0800 Test[23449:1607212] 5秒后恢復(fù)隊列
2020-02-28 15:52:15.136284+0800 Test[23449:1607343] 隊列沒有掛起前添加的任務(wù)執(zhí)行結(jié)束
2020-02-28 15:52:17.132924+0800 Test[23449:1607212] 隊列已經(jīng)恢復(fù)
2020-02-28 15:52:17.132924+0800 Test[23449:1607343] 隊列被掛起之后添加的任務(wù)開始執(zhí)行
由結(jié)果可以知道惨好,dispatch_suspend函數(shù)可以掛起隊列,dispatch_resume函數(shù)可以恢復(fù)隊列随闺,
隊列掛起后不會馬上停止當前在執(zhí)行的任務(wù)日川,而是會執(zhí)行完當前的任務(wù),暫停后面隊列中的任務(wù)矩乐。
4.GCD的延時函數(shù)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (3)( * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
代碼塊
});
這個代碼的意思是在當前時間的3秒后在主隊列執(zhí)行相應(yīng)的代碼塊龄句。