iOS多線程-全面總結(jié)
- 進程和線程
進程:
進程(Process)是計算機中的程序關(guān)于某數(shù)據(jù)集合上的一次運行活動,是系統(tǒng)進行資源分配和調(diào)度的基本單位,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)(百度百科)
根據(jù)百度百科的解釋我們知道進程是系統(tǒng)進行資源分配和調(diào)度的基本單位,在手機端一個進程就是一個app
線程:
線程,有時被稱為輕量級進程(Lightweight Process,LWP),是程序執(zhí)行流的最小單元。一個標(biāo)準(zhǔn)的線程由線程ID,當(dāng)前指令指針(PC),寄存器集合和堆棧組成。(百度百科)
根據(jù)百度百科我們知道,線程來說其實是進程一個實體
一個進程中至少有一條線程,這條線程我們稱為主線程
- 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.(蘋果官方文檔)
官方文檔上說,這是一個基于C語言的創(chuàng)建和使用線程的API,而且是一個跨平臺的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,才會去創(chuàng)建線程加入到當(dāng)前隊列
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)前隊列
[NSThread detachNewThreadWithBlock:^{
[self task];
}]; //@available iOS10
// 4.同上
[NSThread detachNewThreadSelector:@selector(task) toTarget:self withObject:nil];
還有一些實用的熟悉和方法比如
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)心的概念是隊列、任務(wù),不在需要管理線程問題,CGD自動創(chuàng)建、分配、管理線程。
下面我們通過具體的代碼例子,引出結(jié)論和理解:
- 同步隊列
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é)論:
* 串行隊列總結(jié): 串行隊列,特點:保證順序執(zhí)行。
1. 如若同步執(zhí)行,不分配線程,在當(dāng)前線程串行執(zhí)行;
2. 如若,異步執(zhí)行,不阻塞當(dāng)前線程,如果沒有開辟新線程則開辟新線程,如果已經(jīng)開辟了一條線程,則任務(wù)會在開辟的線程中串行執(zhí)行,保持順序執(zhí)行。
死鎖: 造成死鎖的原因就是:相互等待,串行隊列的特點就是順序執(zhí)行,如果同步執(zhí)行任務(wù)在當(dāng)前串行隊列中執(zhí)行,就會造成死鎖。
- 并發(fā)隊列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.haoyuhong.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
/// 并發(fā)隊列,同步任務(wù),不分配線程,在當(dāng)前線程執(zhí)行
dispatch_sync(concurrentQueue, ^{
NSLog(@"1. 當(dāng)前線程: %@", [NSThread currentThread]);
});
/// 并發(fā)隊列,異步任務(wù),分配線程,并發(fā)執(zhí)行
dispatch_async(concurrentQueue, ^{
NSLog(@"2. 當(dāng)前線程: %@", [NSThread currentThread]);
});
/// 并發(fā)隊列,異步任務(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ā)隊列, 特點:并發(fā)執(zhí)行
1. 同步任務(wù),隊列不會分配新線程去執(zhí)行,在當(dāng)前線程串行執(zhí)行
2. 異步任務(wù),隊列分配新線程,所有異步任務(wù),并發(fā)執(zhí)行
-
系統(tǒng)隊列:
- 主隊列
串行隊列,不管是同步還是異步,都不會創(chuàng)建新線程,所有任務(wù)都是在主線程執(zhí)行,所以他是一種特殊的串行隊列。如果當(dāng)前執(zhí)行線程為主線程,添加同步任務(wù)會造成,互相等待狀態(tài),導(dǎo)致死鎖;異步執(zhí)行,等待主線程此異步任務(wù)之前所有任務(wù)執(zhí)行完畢執(zhí)行。
獲取函數(shù):dispatch_get_main_queue() - 全局隊列
并發(fā)隊列。
獲取函數(shù):dispatch_get_global_queue(0, 0)
第一個參數(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
- 主隊列
-
DispatchGroup
dispatch_group: 將隊列添加到隊列組里
隊列組可以添加一個任務(wù)到隊列并且將隊列加入隊列組dispatch_group_create() /// 創(chuàng)建分發(fā)組
dispatch_group_async(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block); /// 添加block任務(wù)到隊列,并且關(guān)聯(lián)到分發(fā)組void
dispatch_group_notify(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block); /// 監(jiān)聽所有隊列里的任務(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 是一個抽象任務(wù)類,不能直接使用,需要實例化兩個子類使用,基于GCD的封裝,將多線程簡單化為隊列和任務(wù),使用起來也是很簡單的
*它與CGD的區(qū)別就是GCD是更底層的封裝,在性能上會比NSOperation好點NSBlockOperation:用一個block的方式初始化一個任務(wù)
實例化:
NSBlockOperation *task1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@”1-%@”, [NSThread currentThread]);
}];NSInvocationOperation:Target-Action的方式初始一個任務(wù)
初始化方式:
NSInvocationOperation *task2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task) object:nil];-
NSOperationQueue :任務(wù)運行隊列
init方式初始:初始化一個并行隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
mianQueue方式獲取主隊列:獲取主隊列,是一個串行隊列
NSOperationQueue *queue = [NSOperationQueue mainQueue];- 直接添加任務(wù)block到隊列
– (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)前隊列:suspended
- 設(shè)置隊列的優(yōu)先級:qualityOfService
- 取消隊列所有任務(wù): cancelAllOperations
- 等待所有隊列任務(wù)執(zhí)行完成:
– (void)waitUntilAllOperationsAreFinished;
- 直接添加任務(wù)block到隊列
添加任務(wù)依賴:一個任務(wù)需要依賴另外一個任務(wù)執(zhí)行完成才能執(zhí)行
– (void)addDependency:(NSOperation *)op;
*移除依賴關(guān)系:
– (void)removeDependency:(NSOperation *)op;
以上iOS多線程中知識,在此做一個總結(jié),一起共勉!