iOS 多執行緒簡單整理NSThread、GCD、NSOperation
iOS Pthreads 和 NSThread
Pthreads:可以在Unix / Linux / Windows 等系統跨平臺使用,使用 C 語言編寫,需要程式設計師自己管理執行緒的生命週期,使用難度較大
NSThread:是蘋果官方提供的,使用起來比 pthread 更加面向物件,簡單易用,可以直接操作執行緒物件。不過也需要需要程式設計師自己管理執行緒的生命週期(主要是建立),運用OC語言。
//使用類方法建立執行緒執行任務
+ (void)detachNewThreadWithBlock:(void (^)(void))block ;
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
//判斷當前是否為多執行緒
+ (BOOL)isMultiThreaded;
//設定當前執行緒優先順序//指定執行緒物件優先順序 0.0~1.0,預設值為0.5
+ (BOOL)setThreadPriority:(double)p;
//例項方法初始化,需要再呼叫start方法
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument;
- (instancetype)initWithBlock:(void (^)(void))block;
另外,還有一個NSObject
//隱式的建立並啟動執行緒,並在指定的執行緒(主執行緒或子執行緒)上執行方法。
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray *)array;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg;
執行緒相關用法
+ (NSThread *)mainThread; // 獲得主執行緒
- (BOOL)isMainThread;// 判斷是否為主執行緒(物件方法)
+ (BOOL)isMainThread;// 判斷是否為主執行緒(類方法)
NSThread *current = [NSThread currentThread]; // 獲得當前執行緒
- (void)setName:(NSString *)n;// 執行緒的名字——setter方法
- (NSString *)name;// 執行緒的名字——getter方法
執行緒狀態控制方法
啟動執行緒方法 // 執行緒進入就緒狀態 -> 執行狀態。當執行緒任務執行完畢,自動進入死亡狀態
- (void)start;
阻塞(暫停)執行緒方法// 執行緒進入阻塞狀態
+ (void)sleepUntilDate:(NSDate *)date;//當前執行緒暫停到某個時間
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;//當前執行緒暫停一段時間
強制停止執行緒 // 執行緒進入死亡狀態
+ (void)exit; 退出當前執行緒
// 在主執行緒上執行操作
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray<NSString *> *)array;
// equivalent to the first method with kCFRunLoopCommonModes
// 在指定執行緒上執行操作
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
// 在當前執行緒上執行操作,呼叫 NSObject 的 performSelector:相關方法
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
iOS GCD
GCD:全名Grand Central Dispatch,中文名郭草地,是基於C語言的一套多執行緒開發API.替換NSThread等執行緒技術,充分利用了裝置多核(自動),使用C語言。
任務管理方式——佇列
兩個通用佇列:
序列佇列:所有任務會在一條執行緒中執行(有可能是當前執行緒也有可能是新開闢的執行緒),並且一個任務執行完畢後,才開始執行下一個任務。(等待完成)
並行佇列:可以開啟多條執行緒並行執行任務(但不一定會開啟新的執行緒),並且當一個任務放到指定執行緒開始執行時,下一個任務就可以開始執行了。(等待發生)
兩個特殊佇列:
主佇列:系統為我們建立好的一個序列佇列,牛逼之處在於它管理必須在主執行緒中執行的任務,屬於有勞保的。
全域性佇列:系統為我們建立好的一個並行佇列,使用起來與我們自己建立的並行佇列無本質差別。
任務執行方式(GCD給出了兩種執行方式——同步執行(sync)和非同步執行(async))
同步執行:在當前執行緒執行任務,不會開闢新的執行緒。必須等到Block函式執行完畢後,dispatch函式才會返回。
非同步執行:可以在新的執行緒中執行任務,但不一定會開闢新的執行緒。dispatch函式會立即返回, 然後Block在後臺非同步執行。
任務佇列組合方式
GCD其他函式用法
GCD 延時執行方法:dispatch_after//該函式用於任務延時執行
GCD 一次性程式碼(只執行一次):dispatch_once//保證函式在整個生命週期內只會執行一次
GCD 佇列組:dispatch_group//佇列組,當加入到佇列組中的所有任務執行完成之後,會呼叫dispatch_group_notify函式通知任務全部完成
GCD 柵欄方法:dispatch_barrier_async//使用此方法建立的任務,會查詢當前佇列中有沒有其他任務要執行,如果有,則等待已有任務執行完畢後再執行,同時,在此任務之後進入佇列的任務,需要等待此任務執行完成後,才能執行
GCD 快速迭代方法:dispatch_apply//該函式用於重複執行某個任務,如果任務佇列是並行佇列,重複執行的任務會併發執行,如果任務佇列為序列佇列,則任務會順序執行,需要注意的是,該函式為同步函式,要防止執行緒阻塞和死鎖
GCD 訊號量:dispatch_semaphore//訊號量是控制任務執行的重要條件,當訊號量為0時,所有任務等待,訊號量越大,允許可並行執行的任務數量越多
NSOperation && NSOperationQueue
NSOperation以及NSOperationQueue是蘋果對於GCD的封裝,其中呢,NSOperation其實就是我們上面所說的任務,但是這個類不能直接使用,我們要用他的兩個子類,NSBlockOperation和NSInvocationOperation,而NSOperationQueue呢,其實就是類似於GCD中的佇列,用於管理你加入到其中的任務。
NSOperation
它提供了關於任務的執行,取消,以及隨時獲取任務的狀態,新增任務依賴以及優先順序等方法和屬性,相對於GCD提供的方法來說,更直觀,更方便,並且提供了更多的控制介面。
- (void)start;//啟動任務 預設加入到當前佇列
- (void)main;//自定義NSOperation,寫一個子類,重寫這個方法,在這個方法裡面新增需要執行的操作。
- (void)addDependency:(NSOperation *)op;//新增依賴
- (void)removeDependency:(NSOperation *)op;//移除依賴
@property NSOperationQueuePriority queuePriority;//執行優先順序
然而NSOperation本身是個抽象類,不能直接使用,我們有三種方式賦予它新的生命,如下
NSOperation第一個,這是我要說的第一個任務型別,我們可以自定義繼承於NSOperation的子類,並重寫父類提供的方法,自定義的任務更具有指向性,它可以滿足你特定的需求
NSBlockOperation 第二個,就是系統提供的NSOperation的子類NSBlockOperation,我們看一下他提供的API:
@interface NSBlockOperation : NSOperation {
@private
id _private2;
void *_reserved2;
}
+ (instancetype)blockOperationWithBlock:(void (^)(void))block;
- (void)addExecutionBlock:(void (^)(void))block;
@property (readonly, copy) NSArray *executionBlocks;
@end
NSInvocationOperation 第三個,就是它了,同樣也是系統提供給我們的一個任務類,基於一個target物件以及一個selector來建立任務,具體程式碼:
-(void)NSInvocationOperationRun{
NSInvocationOperation *invocationOper = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperSel) object:nil];
[invocationOper start];
}
-(void)invocationOperSel{
NSLog(@"NSInvocationOperationRun_%@",[NSThread currentThread]);
}
NSOperationQueue
上面說道我們建立的NSOperation任務物件可以通過start方法來執行,同樣我們可以把這個任務物件新增到一個NSOperationQueue物件中去執行
- (void)addOperation:(NSOperation *)op;//新增任務
- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);//新增一組任務
- (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);//新增一個block形式的任務
-(void)NSOperationQueueRun{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSInvocationOperation *invocationOper = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperSel) object:nil];
[queue addOperation:invocationOper];
NSBlockOperation *blockOper = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperationRun_%@",[NSThread currentThread]);
}];
[queue addOperation:blockOper];
[queue addOperationWithBlock:^{
NSLog(@"QUEUEBlockOperationRun_%@",[NSThread currentThread]);
}];
}
任務的優先順序
新增依賴關係
佇列的最大併發數
執行緒鎖 NSLock @synchronized(要傳入一個同步物件(一般就是self),然後將你需要加鎖的資源放入程式碼塊中,如果該資源有執行緒正在訪問時,會讓其他執行緒等待)