IOS 多線程NSThread、NSOperation、GCD詳解

OS 多線程NSThread、NSOperation、GCD詳解

iOS有三種多線程編程的技術,分別是:
1、NSThread
2、Cocoa NSOperation (iOS多線程編程之NSOperation和NSOperationQueue的使用)
3、GCD 全稱:Grand Central Dispatch( iOS多線程編程之Grand Central Dispatch(GCD)介紹和使用)

這三種編程方式從上到下,抽象度層次是從低到高的,抽象度越高的使用越簡單,也是Apple最推薦使用的。
這篇我們主要介紹和使用NSThread,後面會繼續2、3 的講解和使用。
1.2 三種方式的有缺點介紹:
NSThread:
優點:NSThread 比其他兩個輕量級
缺點:需要自己管理線程的生命週期,線程同步。線程同步對數據的加鎖會有一定的系統開銷
NSThread實現的技術有下面三種:

Technology

Description

Cocoa threads Cocoa implements threads using the NSThread class. Cocoa also provides methods on NSObject for spawning new threads and executing code on already-running threads. For more information, see “Using NSThread” and “Using NSObject to Spawn a Thread.”
POSIX threads POSIX threads provide a C-based interface for creating threads. If you are not writing a Cocoa application, this is the best choice for creating threads. The POSIX interface is relatively simple to use and offers ample flexibility for configuring your threads. For more information, see “Using POSIX Threads”
Multiprocessing Services Multiprocessing Services is a legacy C-based interface used by applications transitioning from older versions of Mac OS. This technology is available in OS X only and should be avoided for any new development. Instead, you should use the NSThread class or POSIX threads. If you need more information on this technology, see Multiprocessing Services Programming Guide.

一般使用cocoa thread 技術。

Cocoa operation
優點:不需要關心線程管理,數據同步的事情,可以把精力放在自己需要執行的操作上。
Cocoa operation 相關的類是 NSOperation ,NSOperationQueue。NSOperation是個抽象類,使用它必須用它的子類,可以實現它或者使用它定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation。創建NSOperation子類的對象,把對象添加到NSOperationQueue隊列裏執行。
GCD
Grand Central Dispatch (GCD)是Apple開發的一個多核編程的解決方法。在iOS4.0開始之後才能使用。GCD是一個替代諸如NSThread, NSOperationQueue, NSInvocationOperation等技術的很高效和強大的技術。現在的iOS系統都升級到6了,所以不用擔心該技術不能使用。

介紹完這三種多線程編程方式,我們這篇先介紹NSThread的使用。
2、NSThread的使用
2.1 NSThread 有兩種直接創建方式:
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
第一個是實例方法,第二個是類方法

2.2參數的意義:
selector :線程執行的方法,這個selector只能有一個參數,而且不能有返回值。
target :selector消息發送的對象
argument:傳輸給target的唯一參數,也可以是nil
第一種方式會直接創建線程並且開始運行線程,第二種方式是先創建線程對象,然後再運行線程操作,在運行線程操作前可以設置線程的優先級等線程信息
2.3 PS:不顯式創建線程的方法:
用NSObject的類方法 performSelectorInBackground:withObject: 創建一個線程:
[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];
2.4 下載圖片的例子:
2.4.1 新建singeView app
新建項目,並在xib文件上放置一個imageView控件。按住control鍵拖到viewControll
er.h文件中創建imageView IBOutlet
ViewController.m中實現:

2.4.2線程間通訊
線程下載完圖片後怎麼通知主線程更新界面呢?
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
performSelectorOnMainThread是NSObject的方法,除了可以更新主線程的數據外,還可以更新其他線程的比如:
用:performSelector:onThread:withObject:waitUntilDone:
運行下載圖片:

IOS 多線程NSThread、NSOperation、GCD詳解 - 第1張  | 未來技術

圖片下載下來了。
2.3 線程同步
我們演示一個經典的賣票的例子來講NSThread的線程同步:
.h

 

如果沒有線程同步的lock,賣票數可能是-1.加上lock之後線程同步保證了數據的正確性。
上面例子我使用了兩種鎖,一種NSCondition ,一種是:NSLock。 NSCondition我已經註釋了。
線程的順序執行
他們都可以通過
[ticketsCondition signal]; 發送信號的方式,在一個線程喚醒另外一個線程的等待。
比如:

wait是等待,我加了一個 線程3 去喚醒其他兩個線程鎖中的wait
其他同步
我們可以使用指令 @synchronized 來簡化 NSLock的使用,這樣我們就不必顯示編寫創建NSLock,加鎖並解鎖相關代碼。

還有其他的一些鎖對象,比如:循環鎖NSRecursiveLock,條件鎖NSConditionLock,分佈式鎖NSDistributedLock等等,可以自己看官方文檔學習

 

iOS多線程之NSOperation

1.NSOperation的理解
NSOperation本身是一個抽象的基類,我們要自己子類化NSOpeartion並封裝我們要完成的任務,系統提供了兩個比較方便的子類NSInvocationOperation和NSBlockOperation,NSInvocationOperation方便我們以現有的方法來初始化一個operation,NSBlockOperation是方便我們從Block來初始化operation。所有的NSOperation都有如下特徵:
1. 支持NSOperation對象之間建立依賴關係,當一個operation的所有依賴的operation都執行完了自己纔會執行。
2. 支持可選的completion block,當operation的主任務完成之後調用。
3. 支持通過KVO通知來監控operation的執行狀態。
4. 支持指定operaion的優先級來安排operation的相對指向順序。
5. 支持operation的取消操作來停止operation執行。
2.NSOperation的執行
通常情況下我們要併發執行的話只要簡單的把operation添加到operation queue中就行,operation queue負責創建線程併發地執行operation任務。

我們也可以直接通過NSOpeartion的start方法來處理operation任務,這樣執行的話任務的處理是在start調用的線程中同步執行的。

isConcurrent屬性返回的就是operation要執行的任務相對於調用start的線程是同步的還是異步的,isConcurrent默認返回NO。當然我們也可以自己創建線程來執行NSOperation的start方法達到併發執行的效果。
3.NSInvocationOperation的使用

 4.NSBlockOperation的使用

NSBlockOperation可以通過addExecutionBlock:方法添加多個block,只有所有block都執行完成的時候,operation纔算是完成。
5.自定義NSOperation
NSOperation提供了一個基本結構,具體相關的併發執行的方法、operation依賴、KVO通知和取消操作還是需要我們自己實現的。整個NSOperation子類實現如下:

併發operation需要實現以下方法:
1. start
2. main
3. isConcurrent
4. isExecuting
5. isFinished
NSOperation支持KVO的屬性有:
1. isCancelled
2. isConcurrent
3. isExecuting
4. isFinished
5. isReady
6. dependencies
7. queuePriority
8. completionBlock
不是所有的屬性都要我們發送KVO通知,如果我們覆蓋了start方法,就要像上面的代碼一樣在適當的地方發出isExecuting和isFinished的通知。如果我們實現了自己的addDependency:或者removeDependency:,就要適當的地方發送dependencies的通知。
6.配置NSOperation
6.1依賴管理
我們可以通過addDependency:給當前operation添加依賴operation,依賴關係不限於operation是否在一個隊列裏。注意我們不要自己生成循環依賴,這樣會造成死鎖。
6.2優先級管理
在隊列裏的operation的執行順序取決於operation的狀態(是否準備就緒)和相對優先級。是否準備就緒取決於operation的依賴operation是否完成,執行隊列會優先考慮operation,如果高優先級的operation沒有準備就緒,執行隊列就會先執行低優先級的operation。operation的相對優先級只針對同一隊列,就是說一個低優先級的operation可能比另一個隊列裏高優先級的operation優先執行。
6.3底層線程優先級管理
我們可以通過setThreadPriority:設置operation系統級別的線程優先級,優先級由0.0到1.0浮點數指定,默認是0.5。我們自己設置的系統級別的線程優先級只針對main方法執行期間有效,其他方法都是按照默認優先級執行。

IOS多線程GCD

Grand Central Dispatch (GCD)是Apple開發的一個多核編程的解決方法。
dispatch queue分成以下三種:
1)運行在主線程的Main queue,通過dispatch_get_main_queue獲取。

可以看出,dispatch_get_main_queue也是一種dispatch_queue_t。
2)並行隊列global dispatch queue,通過dispatch_get_global_queue獲取,由系統創建三個不同優先級的dispatch queue。並行隊列的執行順序與其加入隊列的順序相同。
3)串行隊列serial queues一般用於按順序同步訪問,可創建任意數量的串行隊列,各個串行隊列之間是併發的。
當想要任務按照某一個特定的順序執行時,串行隊列是很有用的。串行隊列在同一個時間只執行一個任務。我們可以使用串行隊列代替鎖去保護共享的數據。和鎖不同,一個串行隊列可以保證任務在一個可預知的順序下執行。
serial queues通過dispatch_queue_create創建,可以使用函數dispatch_retain和dispatch_release去增加或者減少引用計數。
GCD的用法:

一個應用GCD的例子:

GCD的另一個用處是可以讓程序在後臺較長久的運行。
在沒有使用GCD時,當app被按home鍵退出後,app僅有最多5秒鐘的時候做一些保存或清理資源的工作。但是在使用GCD後,app最多有10分鐘的時間在後臺長久運行。這個時間可以用來做清理本地緩存,發送統計數據等工作。
讓程序在後臺長久運行的示例代碼如下:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章