iOS 多線程 總結(jié)

多線程技術(shù)方案

原文地址

  1. pthread
  2. NSThread
  3. GCD
  4. NSOperation

1.pthread

特點

程序員自己管理線程的生命周期

定義

線程庫實行了POSIX線程標準通常稱為Pthreads。
POSIX線程具有很好的可移植性,使用pthreads編寫的代碼可運行于Solaris村缸、FreeBSD自娩、Linux 等平臺透绩,Windows平臺亦有pthreads-win32可供使用 。
Pthreads定義了一套C語言的類型平匈、函數(shù)與常量,它以pthread.h頭文件和一個線程庫實現(xiàn)晋修。

頭文件

#import <pthread.h>

創(chuàng)建線程

/**

- (void)demo {

    
    //1.創(chuàng)建線程對象
    pthread_t thread;
    
    /**2.創(chuàng)建線程
    參數(shù):
     1.指向線程標識符的指針,C 語言中類型的結(jié)尾通常 _t/Ref凰盔,而且不需要使用 *;
     2.用來設(shè)置線程屬性;
     3.指向函數(shù)的指針,傳入函數(shù)名(函數(shù)的地址)墓卦,線程要執(zhí)行的函數(shù)/任務;
     4.運行函數(shù)的參數(shù);
     */
    NSString *param = @"參數(shù)";
    int result = pthread_create(&thread, NULL, func, (__bridge void *)(param));
    if (result == 0) {
        NSLog(@"success")
    } else {
        NSLog(@"failure");
        return;
    }
    
    //3.設(shè)置子線程的狀態(tài)設(shè)置為detached,則該線程運行結(jié)束后會自動釋放所有資源,或者在子線程中添加 pthread_detach(pthread_self()),其中pthread_self()是獲得線程自身的id
    pthread_detach(thread);
 }
 
 void *func(void *param) {
    //在此做耗時操作
    NSLog(@"new thread : %@  參數(shù)是: %@",[NSThread currentThread],(__bridge NSString *)(param));
    
    return NULL;
 }

其他函數(shù)

pthread_t:線程ID
pthread_attr_t:線程屬性
pthread_create():創(chuàng)建一個線程
pthread_exit():終止當前線程
pthread_cancel():中斷另外一個線程的運行
pthread_join():阻塞當前的線程户敬,直到另外一個線程運行結(jié)束
pthread_attr_init():初始化線程的屬性
pthread_attr_setdetachstate():設(shè)置脫離狀態(tài)的屬性(決定這個線程在終止時是否可以被結(jié)合)
pthread_attr_getdetachstate():獲取脫離狀態(tài)的屬性
pthread_attr_destroy():刪除線程的屬性
pthread_kill():向線程發(fā)送一個信號
pthread_equal(): 對兩個線程的線程標識號進行比較
pthread_detach(): 分離線程
pthread_self(): 查詢線程自身線程標識號

2.NSThread

特點

程序員管理線程的生命周期落剪;

使用OC對象, 簡單易用尿庐,可直接操作線程對象

創(chuàng)建方式

1. 實例方法創(chuàng)建線程

- (IBAction)useInstanceMehotd:(id)sender {
    NSLog(@"===== begin %@", [NSThread currentThread]);
    // 創(chuàng)建NSThread 對象
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(myOperation:) object:@"instance method"];
    // 啟動線程 -> 開辟子線程執(zhí)行方法
    [thread start];
    NSLog(@"===== end %@", [NSThread currentThread]);
}

- (void)myOperation:(id)param {
    NSLog(@"begin %@", [NSThread currentThread]);
    NSLog(@"param = %@", param);
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end %@", [NSThread currentThread]);
}

2. 類方法創(chuàng)建線程

- (IBAction)useClassMethod:(id)sender {
    NSLog(@"===== begin %@", [NSThread currentThread]);
    // 自動創(chuàng)建線程忠怖,并執(zhí)行方法
    [NSThread detachNewThreadSelector:@selector(myOperation:) toTarget:self withObject:@"class method"];
    NSLog(@"===== end %@", [NSThread currentThread]);

}

- (void)myOperation:(id)param {
    NSLog(@"begin %@", [NSThread currentThread]);
    NSLog(@"param = %@", param);
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end %@", [NSThread currentThread]);
}

3. NSObject分類方法創(chuàng)建線程

- (IBAction)useCatgoryMethod:(id)sender {
    NSLog(@"===== begin %@", [NSThread currentThread]);
    // 是NSObject分類方法
    // 自動在后臺線程執(zhí)行
    [self performSelectorInBackground:@selector(myOperation:) withObject:@"category method"];
    NSLog(@"===== end %@", [NSThread currentThread]);
}

- (void)myOperation:(id)param {
    NSLog(@"begin %@", [NSThread currentThread]);
    NSLog(@"param = %@", param);
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end %@", [NSThread currentThread]);
}

3.GCD

特點

不用關(guān)心線程的生命周期

執(zhí)行任務方式

  1. 同步的方式執(zhí)行:
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
queue: 隊列
block: 任務
  1. 異步的方式執(zhí)行
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
queue: 隊列
block: 任務


同步:
只能在當前線程中執(zhí)行任務, 不具備開啟線程能力
必須等待任務執(zhí)行完畢抄瑟,才會執(zhí)行下一條語句

異步:
可以在新的線程中執(zhí)行凡泣, 具備開啟新線程能力
不用等待任務執(zhí)行完畢, 就可以執(zhí)行下一條語句

隊列類型

1. 并發(fā)隊列(Concurrent Dispatch Queue)
   * 允許多個任務并發(fā)(同時)執(zhí)行
   * 并發(fā)功能只有在異步函數(shù)下才有效
2. 串行隊列(Serial Dispatch Queue)
   * 讓任務一個接著一個的執(zhí)行

全局隊列(dispatch_get_global_queue): 是一個并發(fā)隊列
主隊列(dispatch_get_main_queue): 主隊列專門用于在主線程上執(zhí)行任務

隊列執(zhí)行效果

        并發(fā)隊列            串行隊列
同步   1.沒有開啟新線程     1. 沒有開啟新線程
       2.串行執(zhí)行任務       2. 串行執(zhí)行任務

異步   1. 開啟新線程        1. 開啟新線程
       2. 并發(fā)執(zhí)行任務      2. 串行執(zhí)行任務

dispatch_barrier|_async 使用

該函數(shù)會等待dispatch_barrier_async 前面所有任務完成

然后在執(zhí)行 dispatch_barrier_async 的任務

- (IBAction)test_barrier_async:(id)sender {
    dispatch_queue_t queue = dispatch_queue_create("com.chenxi.learn.thread", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"task1 complete, %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:1];
        NSLog(@"task2 complete, %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        int time = arc4random() % 5;
        [NSThread sleepForTimeInterval:time];
        NSLog(@"task3 complete, %@", [NSThread currentThread]);
    });
    
    // 阻塞
    dispatch_barrier_async(queue, ^{
        NSLog(@"barrier asycn task ..., %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"another task1 complete, %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:1];
        NSLog(@"another task2 complete, %@", [NSThread currentThread]);
    });
}

GCD 調(diào)度組

使用 dispatch_group_async 和 dispatch_group_notify 函數(shù)來完成調(diào)度組的工作

- (void)demo {
    
    // 1. 調(diào)度組
    dispatch_group_t group = dispatch_group_create();
    
    // 2. 并發(fā)隊列
    dispatch_queue_t queue = dispatch_queue_create("com.chenxi.learn.thread", DISPATCH_QUEUE_CONCURRENT);
    
    // 3. 任務添加到調(diào)度組
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"task1 comolete, %@", [NSThread currentThread]);
    });
    
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:1];
        NSLog(@"task2 comolete, %@", [NSThread currentThread]);
    });
    
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"task3 comolete, %@", [NSThread currentThread]);
    });
    
    // 等待所有任務離開調(diào)度組锐借, 調(diào)用該函數(shù)
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"all task completed, %@", [NSThread currentThread]);
    });
    
    NSLog(@"other things ...");
}

4. NSOperation

特點

是使用OC語言對GCD的封裝

完全面向?qū)ο笪属铮恍枰芾砭€程的生命周期

NSOperation 只是一個抽象類往衷, 需要使用子類來執(zhí)行任務钞翔。 蘋果提供了兩個子類: NSInvocationOperation 和 NSBlockOperation。

核心

操作(NSoperation): 要做的事情

隊列(NSOperationQueue): 存放操作

使用步驟

創(chuàng)建操作

創(chuàng)建隊列

將操作放入隊列

NSInvocationOperation 使用
- (IBAction)tes_invocation:(id)sender {
    
    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@{@"name":@"invocationOperation", @"param": @"hello world"}];
    
    // 操作完成回調(diào)
    [invocationOperation setCompletionBlock:^{
        NSLog(@"end invocation thread = %@", [NSThread currentThread]);
    }];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    [queue addOperation:invocationOperation];
}

- (void)demo:(id)obj {
    [NSThread sleepForTimeInterval:arc4random()%4];
    NSLog(@"thread = %@, msg = %@", [NSThread currentThread], obj);
}
NSBlockOperation
- (IBAction)test_block:(id)sender {
    
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"block operation 1, thread = %@", [NSThread currentThread]);
    }];
    
    // 可以添加多個任務
    [blockOperation addExecutionBlock:^{
        [NSThread sleepForTimeInterval:1];
        NSLog(@"block operation 2, thread = %@", [NSThread currentThread]);
    }];
    
    [blockOperation addExecutionBlock:^{
        [NSThread sleepForTimeInterval:1.5];
        NSLog(@"block operation 3, thread = %@", [NSThread currentThread]);
    }];
    
    [blockOperation setCompletionBlock:^{
        NSLog(@"end block operation, thread = %@", [NSThread currentThread]);
    }];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    [queue addOperation:blockOperation];
}
操作依賴
- (IBAction)test_dependency:(id)sender {
    
    _queue = [[NSOperationQueue alloc] init];
    
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"op1 , thread = %@", [NSThread currentThread]);
    }];
    
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"op2 , thread = %@", [NSThread currentThread]);
    }];
    
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        [NSThread sleepForTimeInterval:0.5];
        NSLog(@"op3 , thread = %@", [NSThread currentThread]);
    }];
    
    // op1 完成之后席舍,開始op2 / op3 任務
    [op2 addDependency:op1];
    [op3 addDependency:op1];
    
    [_queue addOperation:op1];
    [_queue addOperation:op2];
    [_queue addOperation:op3];
    
    NSLog(@"test dependency , thread = %@", [NSThread currentThread]);
}

自定義NSOperation

自定義 Operation 需要繼承 NSOperation 類布轿,并實現(xiàn)其 main() 方法,因為在調(diào)用 start() 方法的時候,內(nèi)部會調(diào)用 main() 方法完成相關(guān)邏輯汰扭。

// 創(chuàng)建 CustomOperation 類稠肘, 繼承自 NSOperation
@interface CustomOperation : NSOperation
@end

@implementation CustomOperation

- (void)main
{
    NSTimeInterval time = arc4random() % 6;
    [NSThread sleepForTimeInterval:time];
    NSLog(@"thread %@", [NSThread currentThread]);
}

@end

// ======= 在其他文件調(diào)用

- (IBAction)test_custom_operation:(id)sender {
    
    CustomOperation *operation1 = [[CustomOperation alloc] init];
    CustomOperation *operation2 = [[CustomOperation alloc] init];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    [queue addOperation:operation1];
    [queue addOperation:operation2];
}

隊列其他方法

maxConcurrentOperationCount 這是最大并發(fā)數(shù)

suspended 隊列暫停/繼續(xù)

cancelAllOperations 取消所有操作

參考
  1. 關(guān)于iOS多線程,你看我就夠了
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末萝毛,一起剝皮案震驚了整個濱河市项阴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌笆包,老刑警劉巖环揽,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異庵佣,居然都是意外死亡歉胶,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門巴粪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來通今,“玉大人,你說我怎么就攤上這事肛根”杷” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵晶通,是天一觀的道長璃氢。 經(jīng)常有香客問我,道長狮辽,這世上最難降的妖魔是什么一也? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮喉脖,結(jié)果婚禮上椰苟,老公的妹妹穿的比我還像新娘。我一直安慰自己树叽,他們只是感情好舆蝴,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著题诵,像睡著了一般洁仗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上性锭,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天赠潦,我揣著相機與錄音,去河邊找鬼草冈。 笑死她奥,一個胖子當著我的面吹牛瓮增,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哩俭,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼绷跑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了凡资?” 一聲冷哼從身側(cè)響起砸捏,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎隙赁,沒想到半個月后带膜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡鸳谜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年膝藕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咐扭。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡芭挽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蝗肪,到底是詐尸還是另有隱情袜爪,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布薛闪,位于F島的核電站辛馆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏豁延。R本人自食惡果不足惜昙篙,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诱咏。 院中可真熱鬧苔可,春花似錦、人聲如沸袋狞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽苟鸯。三九已至同蜻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間早处,已是汗流浹背湾蔓。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留陕赃,地道東北人卵蛉。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像么库,于是被迫代替她去往敵國和親傻丝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容