iOS 多線程開發(fā)

作為一個開發(fā)人員, 有兩個詞無論是工作中還是面試中, 都會經常聽見, 被問及:"進程""線程"炼吴。 在開始了解多線程之前, 先來了解一下這二者的關系和區(qū)別: 簡單點說, 進程是一個有獨立地址空間的, 而線程只是一個進程中執(zhí)行任務的一個路徑, 這是二者有本質的區(qū)別, 可以說他們是不同的操作系統(tǒng)資源的管理方式粱锐。

做iOS開發(fā),很少會涉及到進程。我們一般會做的就是進程間通信剑鞍,從當前App跳轉到第三方App昨凡,例如“QQ”、“微信”或指定App蚁署。我們可能會在跳轉過程中傳遞一些參數便脊,在第三方App上做出相應的操作,這就是我目前涉及到的跟進程有關的開發(fā)光戈。這里我主要還是想講的是線程哪痰,因為,相比之下久妆,線程在我們開發(fā)過程中還是尤為重要的晌杰。

線程

可以說,一個進程是由一個或多個線程組成的筷弦,進程負責調度多條線程肋演, 真正執(zhí)行任務,負責代碼執(zhí)行的是線程烂琴。

在程序被啟動的時候爹殊,系統(tǒng)的主線程就被創(chuàng)建,直到程序完全退出监右,這個線程都會存在边灭。他用來執(zhí)行main函數。這時的主線程要完成所有的操作健盒,網絡請求绒瘦、UI展示、動畫等等扣癣。在只有主線程的情況下這些任務都要按順序一個一個執(zhí)行惰帽, 無法并發(fā)執(zhí)行。所以父虑,我們需要多線程來協(xié)助主線程完成這個并發(fā)執(zhí)行的任務该酗。

iOS多線程

多線程很好理解,有多條線程在執(zhí)行任務士嚎。

它其實是針對單核的CPU設計的呜魄, 因為單核的同一時間只能執(zhí)行一個任務, 但是我們可以利用多線程莱衩,讓CPU快速的在多個線程之間切換爵嗅,從而給我們一種多個任務在同時進行的錯覺。在多核的CPU中笨蚁, 是真實的達到了睹晒, 多個線程同時執(zhí)行任務趟庄。

1. 多線程優(yōu)缺點

優(yōu)點:① 適當的提高代碼執(zhí)行效率

? ? ? ? ? ?② 適當提高資源利用率

缺點:① 開啟線程過多,會占用大量內存空間伪很,所以要適度

? ? ? ? ? ?② 程序設計更復雜戚啥,需要考慮諸如線程安全的問題

2. iOS中的多線程

iOS中多線程主要有四種:NSThread、NSObject锉试、NSOperationQueue猫十、GCD

2.1 ?NSTread 線程類

優(yōu)點:1. 輕量級

? ? ? ? ? ? 2.可以快速創(chuàng)建子線程,并對子線程有控制權

缺點:1. 需要手動管理線程的生命周期

? ? ? ? ? ? 2.要手動開啟子線程键痛、基本信息要手動設置

2.1.1 NSTread的創(chuàng)建

NSTread的創(chuàng)建有三種方式炫彩, 后兩者相當于對第一種進行了封裝,我們不再可以設置線程的基本信息

基本的創(chuàng)建方式:

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadTask) object:nil];

thread.name = @"線程類";

[thread start];

快速創(chuàng)建絮短,并自動開啟:

[NSThread detachNewThreadSelector:@selector(threadTask) toTarget:self withObject:nil];

隱式創(chuàng)建江兢,并自動開啟:

[self performSelectorInBackground:@selector(threadTask) withObject:nil];

這里面線程我讓他執(zhí)行threadTask里面的任務, 里面模擬了線程卡死代碼丁频,并看看當前是在哪執(zhí)任務

- (void)threadTask {

if ([NSThread isMainThread]) {

NSLog(@"當前線程 是 主線程杉允,是%@", [NSThread currentThread]);

} else {

NSLog(@"當前線程 非 主線程,是%@", [NSThread currentThread]);

}

NSInteger num = 0;

for (NSInteger i = 0; i < 1000000000; i++) {

num++;

}

NSLog(@"%ld", num);

[self performSelector:@selector(reloadUIView) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];

}

這里面用到了幾個線程相關的方法:

isMainThread : 查看當前線程是否是主線程(0:非 ?/ ?1:是)

currentThread: 查單當前線程

mainThread: ? ? 獲得主線程

線程間通信:

在某個線程或主線程執(zhí)行某個任務

-(void)performSelector:(SEL)aSelectoron Thread:(NSThread*)thread withObject:(id)arg waitUntilDone:(BOOL)wait;

-(void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;



2.2 GCD

GCD是iOS開發(fā)中應用最為廣泛的多線程開發(fā)技術席里,使用得最簡單叔磷。GCD是蘋果公司自己開發(fā)的,基于C語言寫的奖磁,提供了非常強大的函數改基。

想學懂GCD,不得不先了解一下任務和隊列兩個核心概念

2.2.1 任務和隊列

一咖为、概念:

? ? ? ? 任務:執(zhí)行的操作秕狰,通常是我們代碼中的方法

? ? ? ? 隊列:可以理解為用來存放任務的列表

二、分類:

? ? ? ? 任務的種類(是否開辟新的線程):

? ? ? ? ? ? ? ? ? ? ?同步執(zhí)行(不開辟新線程)躁染,異步執(zhí)行(開辟新線程)

? ? ? ? 隊列的種類(任務的執(zhí)行方式):

? ? ? ? ? ? ? ? ? ? 并行隊列(多個任務可同時執(zhí)行)鸣哀,串行隊列(任務按順序一個一個執(zhí)行)

三、組合:

? ? ? ? 同步執(zhí)行+并行隊列

? ? ? ? 同步執(zhí)行+串行隊列

? ? ? ? 異步執(zhí)行+并行隊列

? ? ? ? 異步執(zhí)行+串行隊列

? ? 還有一種隊列叫主隊列吞彤,是串行我衬。加上這種隊列,又有兩種新組合方式

? ? ? ? 同步執(zhí)行+主隊列

? ? ? ? 異步執(zhí)行+主隊列

2.2.2 GCD的使用步驟

1->創(chuàng)建隊列:

? ? 并行隊列:

dispatch_queue_t queue = dispatch_queue_create("name", DISPATCH_QUEUE_CONCURRENT);

? ? 串行隊列:

dispatch_queue_t queue = dispatch_queue_create("name", DISPATCH_QUEUE_SERIAL);

? ? 主隊列:

dispatch_queue_t queue = dispatch_get_main_queue();

? ?全局隊列:

dispatch_queue_t globa = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);


2->創(chuàng)建任務:

? ? 同步執(zhí)行:

dispatch_sync(queue, ^{

});

? ? 異步執(zhí)行:

dispatch_async(queue, ^{

});

2.2.3 GCD死鎖

GCD死鎖的問題我也是繞了好久才繞明白饰恕。這里來列舉幾個會造成死鎖的案例:

案例1. 主隊列+同步執(zhí)行

// 同步主隊列

- (void)syncMainQueue {

NSLog(@"~~~1~~~");//任務1

dispatch_sync(dispatch_get_main_queue(), ^{

NSLog(@"~~~2~~~");//任務2

});

NSLog(@"~~~3~~~");//任務3

}

執(zhí)行結果:

分析:進入到方法中挠羔,首先執(zhí)行任務1,接下來遇到同步線程的任務2埋嵌,隊列是先進先出的原則褥赊,由于三個任務全都是在主隊列上,同步的任務2實際上是插在了任務3的后面莉恼,但是任務3卻要等任務2執(zhí)行完畢之后才會執(zhí)行拌喉,這樣就形成了任務2和任務3互等的狀態(tài),無法往下執(zhí)行俐银,卡死在這里尿背。

解決:自定義串行隊列,配合同步線程

// 同步串行

- (void)syncSerial {

NSLog(@"~~~1~~~");

dispatch_sync(dispatch_queue_create("同步串行", DISPATCH_QUEUE_SERIAL), ^{

NSLog(@"~~~2~~~");

});

NSLog(@"~~~3~~~");

}

執(zhí)行結果:

分析:

主隊列也是串行隊列捶惜,同樣是同步線程田藐,但結果卻是不一樣的。造成執(zhí)行結果不同的唯一原因就是任務2是執(zhí)行在一個不同于任務1和任務3的隊列中吱七。

來看一下執(zhí)行順序汽久,首先執(zhí)行任務1,接著遇到同步線程的任務2踊餐,在任務2執(zhí)行完畢之后景醇,去執(zhí)行任務3。由于不是在一個隊列中吝岭,任務2是排在了自定義的隊列的第一個位置三痰, 不用等任務3執(zhí)行完就可以去執(zhí)行。窜管、

案例2:在自定義隊列中同步執(zhí)行

- (void)asyncAndSync {

NSLog(@"~~~1~~~");

dispatch_queue_t queue = dispatch_queue_create("串行", DISPATCH_QUEUE_SERIAL);

dispatch_async(queue, ^{

NSLog(@"~~~2~~~");

dispatch_sync(queue, ^{

NSLog(@"~~~3~~~");

});

NSLog(@"~~~4~~~");

});

NSLog(@"~~~5~~~");

}

執(zhí)行結果:

任務3散劫,任務4未執(zhí)行

分析:

? 首先看看5個任務都是在哪個隊列執(zhí)行的 任務1-主隊列、任務2-自定義隊列幕帆、任務3-自定義隊列获搏、任務4-自定義隊列、任務5-主隊列失乾。

再來看看任務的執(zhí)行順序:首先執(zhí)行任務1常熙;接著遇到異步任務,暫時跳過仗扬,執(zhí)行任務5症概;接著進入到異步任務內,執(zhí)行任務2早芭;接下來遇到同步任務3彼城,但是任務3,任務2退个,任務4都是執(zhí)行在自定義的隊列里募壕,所以他排在了任務4后,但是任務4還在等同步隊列執(zhí)行完才執(zhí)行语盈, 所以兩者進入了互等狀態(tài)舱馅,卡死在這里。

2.2.4 GCD對比

2.3 NSOperation 操作類

單獨的NSOperation對象是不能進行多線程編輯的刀荒,它需要配合NSOperationQueue(操作隊列)來實現多線程

首先我們應該知道代嗤,NSOperation是一個抽象類棘钞, 它本事并不具備封裝操作的能力, 所以我們必須創(chuàng)建NSOperation的子類

2.3.1 創(chuàng)建NSOperation

NSOperation的子類有三種:NSInvocationOperation干毅、NSBlockOperation和自定義的繼承于NSOperation的類宜猜。

2.3.2 NSOperation對象的創(chuàng)建與使用

1-> NSInvocationOperation

- (void)invocationOperation {

NSInvocationOperation *operation_1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(logNum) object:nil];

[operation_1 start];

NSInvocationOperation *operation_2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(logNum) object:nil];

[operation_2 start];

}

2-> NSBlockOperation

? ? ? ?這里創(chuàng)建NSBlockOperation對象的方法:

? ? ? ? ? ? ? +(id)blockOperationWithBlock:(void(^)(void))block;

? ? ? ?添加操作:

? ? ? ? ? ? ?-(void)addExecutionBlock:(void(^)(void))block;

- (void)blockOperation {

NSBlockOperation *operation_1 = [NSBlockOperation blockOperationWithBlock:^{

NSLog(@"~~~1.%@~~~", [NSThread currentThread]);

}];

[operation_1 addExecutionBlock:^{

NSLog(@"~~~2.%@~~~", [NSThread currentThread]);

}];

[operation_1 addExecutionBlock:^{

NSLog(@"~~~3.%@~~~", [NSThread currentThread]);

}];

[operation_1 addExecutionBlock:^{

NSLog(@"~~~4.%@~~~", [NSThread currentThread]);

}];

[operation_1 addExecutionBlock:^{

NSLog(@"~~~5.%@~~~", [NSThread currentThread]);

}];

[operation_1 start];

}

執(zhí)行結果:

多打印幾次會發(fā)現末荐,執(zhí)行操作的線程是不確定的揉稚;

3->自定義類

自定義的繼承于NSOperation的類需要重寫main方法

2.3.3 NSOperationQueue

// 創(chuàng)建隊列

NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];

// 設置最大并發(fā)數(同時可處理的線程的個數)

[queue setMaxConcurrentOperationCount:2];

// 創(chuàng)建任務

MyOperation *op1 = [[MyOperation alloc] init];

MyOperation *op2 = [[MyOperation alloc] init];

// 添加到隊列

[queue addOperation:op1];

[queue addOperation:op2];

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末虱饿,一起剝皮案震驚了整個濱河市劝枣,隨后出現的幾起案子贸弥,更是在濱河造成了極大的恐慌欲芹,老刑警劉巖娇未,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嚼鹉,死亡現場離奇詭異徽缚,居然都是意外死亡憨奸,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門猎拨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來膀藐,“玉大人,你說我怎么就攤上這事红省《罡鳎” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵吧恃,是天一觀的道長虾啦。 經常有香客問我,道長痕寓,這世上最難降的妖魔是什么傲醉? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮呻率,結果婚禮上硬毕,老公的妹妹穿的比我還像新娘。我一直安慰自己礼仗,他們只是感情好吐咳,可當我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著元践,像睡著了一般韭脊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上单旁,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天沪羔,我揣著相機與錄音,去河邊找鬼象浑。 笑死蔫饰,一個胖子當著我的面吹牛琅豆,可吹牛的內容都是我干的。 我是一名探鬼主播死嗦,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼趋距,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了越除?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤外盯,失蹤者是張志新(化名)和其女友劉穎摘盆,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體饱苟,經...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡孩擂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了箱熬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片类垦。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖城须,靈堂內的尸體忽然破棺而出蚤认,到底是詐尸還是另有隱情,我是刑警寧澤糕伐,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布砰琢,位于F島的核電站,受9級特大地震影響良瞧,放射性物質發(fā)生泄漏陪汽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一褥蚯、第九天 我趴在偏房一處隱蔽的房頂上張望挚冤。 院中可真熱鬧,春花似錦赞庶、人聲如沸训挡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舍哄。三九已至,卻和暖如春誊锭,著一層夾襖步出監(jiān)牢的瞬間表悬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工丧靡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蟆沫,地道東北人籽暇。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像饭庞,于是被迫代替她去往敵國和親戒悠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內容