
線程與多線程相關概念
進程
- 資源分配的最小獨立單元,進程是具有一定獨立功能的程序關于某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位
線程
- 進程下的一個分支,是進程的實體,是CPU調度和分派的基本單元,它是比進程更小的能獨立運行的基本單位,線程自己基本不擁有系統資源,只擁有一點在運行中必不可少的資源(程序計數器、一組寄存器、棧),但是它可與同屬一個進程的其他線程共享進程所擁有的全部資源。
進程和線程的主要差別
- 在于它們是不同的操作系統資源管理方式。進程有獨立的地址空間,一個進程崩潰后,在保護模式下不會對其它進程產生影響,而線程只是一個進程中的不同執行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進程死掉,所以多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。
重要概念(非常非常重要,不能理解這些概念多線程這輩子也學不會)
任務:即操作,你想要干什么,說白了就是一段代碼,在 GCD 中就是一個 Block
隊列:用于存放任務
同步和異步:同步異步概念面向的是任務。同步指第一個任務不執行完,不會開始第二個,異步是不管第一個有沒有執行完,都開始第二個。
串行和并行:串行并行概念面向的是隊列。串行是多個任務按一定順序執行,并行是多個任務同時執行
iOS中隊列的種類有
- 串行隊列:隊列中的任務只會順序執行
- 并行隊列: 隊列中的任務通常會并發執行
- 主隊列:每一個應用程序對應唯一主隊列,直接GET即可;在多線程開發中,使用主隊列更新UI
- 全局隊列:是系統的,直接拿過來(GET)用就可以;與并行隊列類似
iOS中常用的多線程技術
pthread "已被拋棄"
NSThread
NSOperation
GCD
NSThread
NSThread是OC語言面向對象的多線程方案。所以你可以直接操控線程對象,非常直觀和方便。但是,它的生命周期還是需要我們手動管理,所以這套方案只有在一些非常簡單的場景才會用
創建并自動啟動
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];```
- 獲取當前線程
```swift
[NSThread currentThread];```
- 獲取主線程
```swift
[NSThread mainThread];```
----
####GCD
- GCD(Grand Central Dispatch)是基于C語言開發的一套多線程開發機制,也是目前蘋果官方推薦的多線程開發方法。它會自動合理地利用更多的CPU內核(比如雙核、四核),最重要的是它會自動管理線程的生命周期(創建線程、調度任務、銷毀線程),完全不需要我們管理,我們只需要告訴干什么就行。
####隊列
- 獲取主隊列
dispatch_queue_t queue = dispatch_get_main_queue();```
- 獲取全局并行隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);```
----
####創建隊列
- 創建串行隊列
dispatch_queue_t queue = dispatch_queue_create("testQueue", NULL);```
- 創建并行隊列
dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);```
####任務
- 創建同步任務
dispatch_sync(queue1, ^{
});```
- 創建異步任務
dispatch_async(queue2, ^{
});```
----
####隊列組
- 隊列組可以將很多隊列添加到一個組里,這樣做的好處是,當這個組里所有的任務都執行完了,隊列組會通過一個方法通知我們
1、創建隊列組
dispatch_group_t group = dispatch_group_create();
2、創建隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3、使用隊列組的方法執行任務
dispatch_group_async(group, queue, ^{
});
4、當隊列組的方法全部執行完后,會執行
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
});```
線程死鎖
- 簡單的說,就是在當前串行隊列中添加一個同步任務,因為隊列是串行的只能一個一個的執行任務,而同步任務會阻塞隊列,這樣必須等該同步任務執行完才能執行其他任務,但是該同步任務又是其他任務的一部分,所以兩個任務互相等待一直阻塞隊列,這就是線程死鎖。
NSOperation
NSOperation 是蘋果公司對 GCD 的封裝,完全面向對象,所以使用起來更好理解。 大家可以看到 NSOperation 和 NSOperationQueue 分別對應 GCD 的 任務 和 隊列 。
任務
NSOperation 只是一個抽象類,所以不能封裝任務。但它有 2 個子類用于封裝任務。分別是:NSInvocationOperation
和NSBlockOperation
。創建一個 Operation 后,需要調用 start 方法來啟動任務,它會默認在當前隊列同步執行。通過NSInvocationOperation創建任務
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];```
- 通過NSBlockOperation創建任務
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
}];```
- NSBlockOperation 還有一個方法:
addExecutionBlock:
,通過這個方法可以給 Operation 添加多個執行Block
。
隊列
獲取主隊列
NSOperationQueue *queue = [NSOperationQueue mainQueue];
創建其他隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
往隊列中添加任務
[queue addOperation:operation];
NSOperationQueue有一個屬性maxConcurrentOperationCount代表最大并發數,用來設置最多可以讓多少個任務同時執行。當設置為 1 的時候,就是串行隊列。```
----
####線程依賴
- NSOperation 有一個非常實用的功能,那就是添加依賴。比如有 3 個任務:A: 從服務器上下載一張圖片,B:給這張圖片加個水印,C:把圖片返回給服務器。
- 這時就可以用到依賴了
[operation2 addDependency:operation1];
[operation3 addDependency:operation2];
[queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];```
- 返回主線程的方法
NSThread
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:NO];
GCD
dispatch_async(dispatch_get_main_queue(), ^{
});```
####NSOperation
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];```
線程同步
所謂線程同步就是為了防止多個線程搶奪同一個資源造成的數據安全問題,所采取的一種措施。
互斥鎖 :給需要同步的代碼塊加一個互斥鎖,就可以保證每次只有一個線程訪問此代碼塊。
@synchronized(self) {
//需要執行的代碼塊
}```
- 同步執行 :我們可以把多個線程都要執行此段代碼添加到同一個串行隊列,這樣就實現了線程同步的概念。