iOS多線程-全面總結(jié)
- 進(jìn)程和線程
進(jìn)程:
進(jìn)程(Process)是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng)尘分,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位衩椒,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)(百度百科)
根據(jù)百度百科的解釋我們知道進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位教届,在手機(jī)端一個(gè)進(jìn)程就是一個(gè)app
線程:
線程茎截,有時(shí)被稱為輕量級進(jìn)程(Lightweight Process知牌,LWP)丹拯,是程序執(zhí)行流的最小單元站超。一個(gè)標(biāo)準(zhǔn)的線程由線程ID,當(dāng)前指令指針(PC)乖酬,寄存器集合和堆棧組成死相。(百度百科)
根據(jù)百度百科我們知道,線程來說其實(shí)是進(jìn)程一個(gè)實(shí)體
一個(gè)進(jìn)程中至少有一條線程咬像,這條線程我們稱為主線程
- iOS中的創(chuàng)建線程和操作線程
- pThread:純c語言編寫,需要自己管理線程的聲明周期
OS X and iOS provide C-based support for creating threads using the POSIX thread API. This technology can actually be used in any type of application (including Cocoa and Cocoa Touch applications) and might be more convenient if you are writing your software for multiple platforms. The POSIX routine you use to create threads is called, appropriately enough, pthread_create.(蘋果官方文檔)
官方文檔上說算撮,這是一個(gè)基于C語言的創(chuàng)建和使用線程的API,而且是一個(gè)跨平臺(tái)的API县昂。查看官方文檔https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/10000057i-CH15-SW12
- NSThread:OC封裝面向?qū)ο蟀构瘢枰约汗芾砭€程釋放,相對用起來比較簡單
四種創(chuàng)建方式:
// 1.需要調(diào)用start倒彰,才會(huì)去創(chuàng)建線程加入到當(dāng)前隊(duì)列
NSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(task) object:nil];
// 2.iOS10新加入的方法审洞,同上
NSThread *thread = [[NSThread alloc] initWithBlock:^{
}];
[myThread start]; // Actually create the thread
// 3.detach 直接創(chuàng)建線程,加入當(dāng)前隊(duì)列
[NSThread detachNewThreadWithBlock:^{
[self task];
}]; //@available iOS10
// 4.同上
[NSThread detachNewThreadSelector:@selector(task) toTarget:self withObject:nil];
還有一些實(shí)用的熟悉和方法比如
currentThread待讳、isMultiThreaded芒澜、
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
+ (void)exit; 等等如果查看NSThread.h文件
pThread缩赛、NSThread 都需要我們自己去創(chuàng)建管理線程的聲明周期,所以之后出現(xiàn)了不要我們管理線程的生命周期的 GCD撰糠、NSOpration酥馍。
- GCD:API基于C語言, 我們需要關(guān)心的概念是隊(duì)列、任務(wù)阅酪,不在需要管理線程問題旨袒,CGD自動(dòng)創(chuàng)建、分配术辐、管理線程砚尽。
下面我們通過具體的代碼例子,引出結(jié)論和理解:
- 同步隊(duì)列
NSLog(@"當(dāng)前線程:%@", [NSThread currentThread]);
dispatch_queue_t testQueue = dispatch_queue_create("com.haoyuhong.testQueue", NULL);
/// 同步執(zhí)行辉词, 當(dāng)前主線程串行執(zhí)行
dispatch_sync(testQueue, ^{
NSLog(@"2. 當(dāng)前線程: %@", [NSThread currentThread]);
});
/// 異步執(zhí)行必孤, 分配新線程執(zhí)行
dispatch_async(testQueue, ^{
NSLog(@"3. 當(dāng)前線程: %@", [NSThread currentThread]);
});
/// 異步執(zhí)行,在已經(jīng)分配的線程串行執(zhí)行
dispatch_async(testQueue, ^{
NSLog(@"4. 當(dāng)前線程: %@", [NSThread currentThread]);
});
輸出結(jié)果
當(dāng)前線程:<NSThread: 0x600002899240>{number = 1, name = main}
2019-09-03 15:50:48.125511+0800 TestGCD[95991:16450263] 2. 當(dāng)前線程: <NSThread: 0x600002899240>{number = 1, name = main}
2019-09-03 15:50:48.125671+0800 TestGCD[95991:16450326] 3. 當(dāng)前線程: <NSThread: 0x6000028c1b40>{number = 3, name = (null)}
2019-09-03 15:50:48.125765+0800 TestGCD[95991:16450326] 4. 當(dāng)前線程: <NSThread: 0x6000028c1b40>{number = 3, name = (null)}
我們得出以下結(jié)論:
* 串行隊(duì)列總結(jié): 串行隊(duì)列瑞躺,特點(diǎn):保證順序執(zhí)行敷搪。
1. 如若同步執(zhí)行,不分配線程幢哨,在當(dāng)前線程串行執(zhí)行赡勘;
2. 如若,異步執(zhí)行捞镰,不阻塞當(dāng)前線程闸与,如果沒有開辟新線程則開辟新線程,如果已經(jīng)開辟了一條線程岸售,則任務(wù)會(huì)在開辟的線程中串行執(zhí)行践樱,保持順序執(zhí)行。
死鎖: 造成死鎖的原因就是:相互等待凸丸,串行隊(duì)列的特點(diǎn)就是順序執(zhí)行拷邢,如果同步執(zhí)行任務(wù)在當(dāng)前串行隊(duì)列中執(zhí)行,就會(huì)造成死鎖甲雅。
- 并發(fā)隊(duì)列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.haoyuhong.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
/// 并發(fā)隊(duì)列解孙,同步任務(wù),不分配線程抛人,在當(dāng)前線程執(zhí)行
dispatch_sync(concurrentQueue, ^{
NSLog(@"1. 當(dāng)前線程: %@", [NSThread currentThread]);
});
/// 并發(fā)隊(duì)列弛姜,異步任務(wù),分配線程妖枚,并發(fā)執(zhí)行
dispatch_async(concurrentQueue, ^{
NSLog(@"2. 當(dāng)前線程: %@", [NSThread currentThread]);
});
/// 并發(fā)隊(duì)列廷臼,異步任務(wù),分配線程,并發(fā)執(zhí)行
dispatch_async(concurrentQueue, ^{
NSLog(@"3. 當(dāng)前線程: %@", [NSThread currentThread]);
});
## 輸出結(jié)果
2019-09-03 15:50:48.126185+0800 TestGCD[95991:16450263] 1. 當(dāng)前線程: <NSThread: 0x600002899240>{number = 1, name = main}
2019-09-03 15:50:48.126313+0800 TestGCD[95991:16450326] 2. 當(dāng)前線程: <NSThread: 0x6000028c1b40>{number = 3, name = (null)}
2019-09-03 15:50:48.126345+0800 TestGCD[95991:16450325] 3. 當(dāng)前線程: <NSThread: 0x6000028d1b80>{number = 5, name = (null)}
總結(jié)如下
并發(fā)隊(duì)列荠商, 特點(diǎn):并發(fā)執(zhí)行
1. 同步任務(wù)寂恬,隊(duì)列不會(huì)分配新線程去執(zhí)行,在當(dāng)前線程串行執(zhí)行
2. 異步任務(wù)莱没,隊(duì)列分配新線程初肉,所有異步任務(wù),并發(fā)執(zhí)行
-
系統(tǒng)隊(duì)列:
- 主隊(duì)列
串行隊(duì)列饰躲,不管是同步還是異步牙咏,都不會(huì)創(chuàng)建新線程,所有任務(wù)都是在主線程執(zhí)行嘹裂,所以他是一種特殊的串行隊(duì)列妄壶。如果當(dāng)前執(zhí)行線程為主線程,添加同步任務(wù)會(huì)造成寄狼,互相等待狀態(tài)丁寄,導(dǎo)致死鎖;異步執(zhí)行泊愧,等待主線程此異步任務(wù)之前所有任務(wù)執(zhí)行完畢執(zhí)行伊磺。
獲取函數(shù):dispatch_get_main_queue() - 全局隊(duì)列
并發(fā)隊(duì)列。
獲取函數(shù):dispatch_get_global_queue(0, 0)
第一個(gè)參數(shù)拼卵,服務(wù)質(zhì)量決定任務(wù)執(zhí)行的優(yōu)先級
The quality of service you want to give to tasks executed using this queue. Quality-of-service helps determine the priority given to tasks executed by the queue.QOS_CLASS_USER_INTERACTIVE, QOS_CLASS_USER_INITIATED, QOS_CLASS_UTILITY, or QOS_CLASS_BACKGROUND
- 主隊(duì)列
-
DispatchGroup
dispatch_group: 將隊(duì)列添加到隊(duì)列組里
隊(duì)列組可以添加一個(gè)任務(wù)到隊(duì)列并且將隊(duì)列加入隊(duì)列組dispatch_group_create() /// 創(chuàng)建分發(fā)組
dispatch_group_async(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block); /// 添加block任務(wù)到隊(duì)列奢浑,并且關(guān)聯(lián)到分發(fā)組void
dispatch_group_notify(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block); /// 監(jiān)聽所有隊(duì)列里的任務(wù)都完成后執(zhí)行block里的任務(wù)dispatch_group_wait(group, DISPATCH_TIME_FOREVER); /// 同步等待所有之前加入的任務(wù)都執(zhí)行完畢
-
柵欄函數(shù)
柵欄函數(shù):保證之前加入的任務(wù)都執(zhí)行完畢,之后加入的任務(wù)等待柵欄任務(wù)執(zhí)行完畢腋腮。- dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
- void
dispatch_barrier_sync(dispatch_queue_t queue,
DISPATCH_NOESCAPE dispatch_block_t block);
void
-
延遲執(zhí)行:
- dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block);
- dispatch_after(dispatch_time_t when,
-
執(zhí)行一次函數(shù):應(yīng)用于單利的創(chuàng)建
- dispatch_once(dispatch_once_t *predicate,
DISPATCH_NOESCAPE dispatch_block_t block);
- dispatch_once(dispatch_once_t *predicate,
-
NSOperation
NSOperation 是一個(gè)抽象任務(wù)類,不能直接使用壤蚜,需要實(shí)例化兩個(gè)子類使用即寡,基于GCD的封裝,將多線程簡單化為隊(duì)列和任務(wù)袜刷,使用起來也是很簡單的
*它與CGD的區(qū)別就是GCD是更底層的封裝聪富,在性能上會(huì)比NSOperation好點(diǎn)NSBlockOperation:用一個(gè)block的方式初始化一個(gè)任務(wù)
實(shí)例化:
NSBlockOperation *task1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@”1-%@”, [NSThread currentThread]);
}];NSInvocationOperation:Target-Action的方式初始一個(gè)任務(wù)
初始化方式:
NSInvocationOperation *task2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task) object:nil];-
NSOperationQueue :任務(wù)運(yùn)行隊(duì)列
init方式初始:初始化一個(gè)并行隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
mianQueue方式獲取主隊(duì)列:獲取主隊(duì)列,是一個(gè)串行隊(duì)列
NSOperationQueue *queue = [NSOperationQueue mainQueue];- 直接添加任務(wù)block到隊(duì)列
– (void)addOperationWithBlock:(void (^)(void))block API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)); - 設(shè)置并發(fā)數(shù):maxConcurrentOperationCount
- 掛起當(dāng)前隊(duì)列:suspended
- 設(shè)置隊(duì)列的優(yōu)先級:qualityOfService
- 取消隊(duì)列所有任務(wù): cancelAllOperations
- 等待所有隊(duì)列任務(wù)執(zhí)行完成:
– (void)waitUntilAllOperationsAreFinished;
- 直接添加任務(wù)block到隊(duì)列
添加任務(wù)依賴:一個(gè)任務(wù)需要依賴另外一個(gè)任務(wù)執(zhí)行完成才能執(zhí)行
– (void)addDependency:(NSOperation *)op;
*移除依賴關(guān)系:
– (void)removeDependency:(NSOperation *)op;
以上iOS多線程中知識(shí)著蟹,在此做一個(gè)總結(jié)墩蔓,一起共勉!