iOS 多線程小結

關于多線程

  • 概念:
  • 同一個進程中同時開啟多個線程,每條線程執(zhí)行不同的任務婶溯。
  • 本質:速度快
  • 同一時間鲸阔,CPU只能處理一條線程,意味著只有一條線程在執(zhí)行迄委。
  • CPU以人類難以察覺的速度在不同的線程之間切換褐筛,造成多條線程并發(fā)執(zhí)行的假象。
  • 如果線程非常非常多叙身,CPU切換頻繁渔扎,消耗大量資源,線程執(zhí)行效率降低信轿。
  • 優(yōu)點:
  • 多條線程同時(并發(fā))執(zhí)行晃痴,提高程序的執(zhí)行效率。
  • 提高資源利用率财忽,包括CPU倘核、內存等。
  • 缺點
  • 開啟新線程會占用一定內存即彪,線程過多會降低性能紧唱。
  • 2.程序設計更加復雜,比如線程之間的通信隶校、多條線程的數(shù)據(jù)共享漏益。
  • 附:本文目錄


    iOS多線程.png

一、基本概念

  • 進程
  • 可以理解成一個運行中的應用程序深胳,是系統(tǒng)進行資源分配和調度的基本單位绰疤,是操作系統(tǒng)結構的基礎,主要管理資源舞终。
  • 每個進程之間是獨立的峦睡,每個進程均運行在其專用且受保護的內存空間內翎苫。
  • 線程
  • 線程是進程的基本執(zhí)行單元,即進程想要執(zhí)行任務榨了,必須得有線程煎谍。
  • 程序執(zhí)行流的最小單元,線程是進程中的一個實體龙屉。
  • 同步線程
  • 在當前線程內按照創(chuàng)建的先后順序依次執(zhí)行呐粘,不開啟新線程。
  • 異步線程
  • 在當前線程內開啟多個新的線程转捕,同時運行作岖,無先后關系。
  • 隊列
  • 裝載線程任務的隊形結構五芝。
  • 并發(fā)
  • 線程執(zhí)行可以同時一起進行執(zhí)行痘儡。
  • 串行
  • 線程執(zhí)行只能依次逐一先后有序的執(zhí)行。
  • 線程通訊
  • 在一個進程中枢步,通常有多個線程沉删,線程不是孤立存在的,線程之前需要"溝通交流"醉途。
注意點
  • 一個進程可有多個線程矾瑰。
  • 一個進程可有多個隊列。
  • 隊列可分并發(fā)隊列和串行隊列隘擎。

二殴穴、創(chuàng)建方式

  • NSThread
  • 每個NSThread對象對應一個線程,真正最原始的線程货葬。
  • 優(yōu)點
  • NSThread 輕量級最低采幌,相對簡單。
  • 可直接操作線程對象震桶。
  • 缺點
  • 手動管理所有的線程活動植榕,如生命周期、線程同步尼夺、睡眠等尊残。
  • NSOperation
  • 自帶線程管理的抽象類。
  • 優(yōu)點
  • 自帶線程周期管理淤堵,操作上可更注重自己邏輯寝衫。
  • 缺點
  • 面向對象的抽象類,只能實現(xiàn)它或者使用它定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation拐邪。
  • GCD

*Grand Central Dispatch是由蘋果開發(fā)的一個多核編程的解決方案慰毅。iOS4.0+才能使用。

  • 優(yōu)點
  • 最高效扎阶,避開并發(fā)陷阱汹胃。
  • 蘋果官方推薦使用婶芭。
  • 使用比上面2種更為簡單。
  • 性能更好着饥,GCD自動根據(jù)系統(tǒng)負載來增減線程數(shù)量犀农,這就減少了上下文切換以及增加了計算效率。
  • 開發(fā)者只需要告訴 GCD 想要如何執(zhí)行什么任務宰掉,不需要編寫任何線程管理代碼呵哨。
  • 缺點
  • 基于C實現(xiàn)。

三轨奄、如何選擇

  • 簡單而安全的選擇NSOperation實現(xiàn)多線程即可孟害。
  • 處理大量并發(fā)數(shù)據(jù),又追求性能效率的選擇GCD挪拟。
  • NSThread本人選擇基本上是在做些小測試上使用挨务。
  • 個人推薦使用gcd。

四玉组、生命周期

  • 無論使用哪種方式創(chuàng)建的線程谎柄,在正常情況下它的生命周期都是一樣的。


    狀態(tài)示意圖.png
  • 概念
    新建:實例化線程對象

  • 就緒:向線程對象發(fā)送start消息球切,線程對象被加入可調度線程池等待CPU調度。
  • 運行:CPU 負責調度可調度線程池中線程的執(zhí)行绒障。線程執(zhí)行完成之前吨凑,狀> * 態(tài)可能會在就緒和運行之間來回切換。就緒和運行之間的狀態(tài)變化由CPU負> * 責户辱,程序員不能干預鸵钝。
  • 阻塞:當滿足某個預定條件時,可以使用休眠或鎖庐镐,阻塞線程執(zhí)行恩商。sleepForTimeInterval(休眠指定時長),sleepUntilDate(休眠到指定日期)必逆,@synchronized(self):(互斥鎖)怠堪。
  • 死亡:正常死亡,線程執(zhí)行完畢名眉。非正常死亡粟矿,當滿足某個條件后,在線程> * 內部中止執(zhí)行/在主線程中止線程對象
  • 還有線程的exit和cancel
  • [NSThread exit]:一旦強行終止線程损拢,后續(xù)的所有代碼都不會被執(zhí)行陌粹。
  • [thread cancel]取消:并不會直接取消線程,只是給線程對象添加 isCancelled 標記福压。

五掏秩、使用方法(詳細介紹GCD的使用方法)

  • NSThread 創(chuàng)建線程
    //動態(tài)創(chuàng)建線程
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction:) object:@"one"];
    thread.threadPriority = 1;
    [thread start];
    
    //靜態(tài)創(chuàng)建線程
    [NSThread detachNewThreadSelector:@selector(threadAction:) toTarget:self withObject:@"two"];
    
    //隱式創(chuàng)建線程
    [self performSelectorInBackground:@selector(threadAction:) withObject:@"three"];

   //響應方法
    -(void)threadAction:(id)object
    {
        NSLog(@"object = %@",object);
    }
  • 線程通訊
//在指定線程上執(zhí)行操作
[self performSelector:@selector(threadAction:) onThread:thread withObject:nil waitUntilDone:YES]; 
//在主線程上執(zhí)行操作
[self performSelectorOnMainThread:@selector(threadAction:) withObject:nil waitUntilDone:YES]; 
//在當前線程執(zhí)行操作
[self performSelector:@selector(threadAction:) withObject:nil];
  • NSOperation
//NSInvocationOperation創(chuàng)建線程或舞。
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(threadAction:) object:@"six"];
//[invocationOperation start];//直接會在當前線程主線程執(zhí)行
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperation:invocationOperation];

GCD

1.任務和隊列
  • 1.1 任務
  • 就是執(zhí)行操作的意思,換句話說就是你在線程中執(zhí)行的那段代碼蒙幻。在 GCD 中是放在 block 中的映凳。
  • 執(zhí)行任務有兩種方式:同步執(zhí)行(sync)和異步執(zhí)行(async)。兩者的主要區(qū)別是:是否等待隊列的任務執(zhí)行結束杆煞,以及是否具備開啟新線程的能力魏宽。
同步執(zhí)行(sync):
    * 同步添加任務到指定的隊列中,在添加的任務執(zhí)行結束之前决乎,會一直等待,直到隊列里面的任務完成之后再繼續(xù)執(zhí)行队询。
    * 只能在當前線程中執(zhí)行任務,不具備開啟新線程的能力构诚。
異步執(zhí)行(async):
    * 異步添加任務到指定的隊列中蚌斩,它不會做任何等待,可以繼續(xù)執(zhí)行任務范嘱。
    * 可以在新的線程中執(zhí)行任務送膳,具備開啟新線程的能力。

1.2 隊列

  • 這里的隊列指執(zhí)行任務的等待隊列丑蛤,即用來存放任務的隊列叠聋。隊列是一種特殊的線性表,采用 FIFO(先進先出)的原則受裹,即新任務總是被插入到隊列的末尾碌补,而讀取任務的時候總是從隊列的頭部開始讀取。每讀取一個任務棉饶,則從隊列中釋放一個任務厦章。
  • 在 GCD 中有兩種隊列:串行隊列和并發(fā)隊列。兩者都符合 FIFO(先進先出)的原則照藻。兩者的主要區(qū)別是:執(zhí)行順序不同袜啃,以及開啟線程數(shù)不同。
串行隊列(Serial Dispatch Queue):
     * 每次只有一個任務被執(zhí)行幸缕。讓任務一個接著一個地執(zhí)行群发。(只開啟一個線程,一個任務執(zhí)行完畢后发乔,再執(zhí)行下一個任務)
     * 對于串行隊列也物,GCD 提供了的一種特殊的串行隊列:主隊列(Main Dispatch Queue),所有放在主隊列中的任務,都會放到主線程中執(zhí)行列疗。
并發(fā)隊列(Concurrent Dispatch Queue):
     * 可以讓多個任務并發(fā)(同時)執(zhí)行滑蚯。(可以開啟多個線程,并且同時執(zhí)行任務)
注意:并發(fā)隊列的并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效
     * 對于并發(fā)隊列,GCD 默認提供了全局并發(fā)隊列(Global Dispatch Queue)告材。
2. GCD使用步驟
  • 創(chuàng)建一個隊列(串行隊列或并發(fā)隊列)
  • 將任務追加到任務的等待隊列中坤次,然后系統(tǒng)就會根據(jù)任務類型執(zhí)行任務(同步執(zhí)行或異步執(zhí)行)
3. 隊列的創(chuàng)建
  • 可以使用dispatch_queue_create來創(chuàng)建隊列,需要傳入兩個參數(shù)斥赋,第一個參數(shù)表示隊列的唯一標識符缰猴,用于 DEBUG,可為空疤剑,Dispatch Queue 的名稱推薦使用應用程序 ID 這種逆序全程域名滑绒;第二個參數(shù)用來識別是串行隊列還是并發(fā)隊列。DISPATCH_QUEUE_SERIAL 表示串行隊列隘膘,DISPATCH_QUEUE_CONCURRENT 表示并發(fā)隊列疑故。
// 串行隊列的創(chuàng)建方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
// 并發(fā)隊列的創(chuàng)建方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);
4. 任務的創(chuàng)建
  • GCD 提供了同步執(zhí)行任務的創(chuàng)建方法dispatch_sync和異步執(zhí)行任務創(chuàng)建方法dispatch_async。
// 同步執(zhí)行任務創(chuàng)建方法
dispatch_sync(queue, ^{
    // 這里放同步執(zhí)行任務代碼
});
// 異步執(zhí)行任務創(chuàng)建方法
dispatch_async(queue, ^{
    // 這里放異步執(zhí)行任務代碼
});
5. 基本使用
組合方式對比.png
  • 同步執(zhí)行 + 并發(fā)隊列


    同步執(zhí)行 + 并發(fā)隊列.png

    從上圖可以看出:

  • 所有任務都是在當前線程(主線程)中執(zhí)行的弯菊,沒有開啟新的線程(同步執(zhí)行不具備開啟新線程的能力)纵势。
  • 所有任務都在打印的syncConcurrent---begin和syncConcurrent---end之間執(zhí)行的(同步任務需要等待隊列的任務執(zhí)行結束)。
  • 任務按順序執(zhí)行的管钳。按順序執(zhí)行的原因:雖然并發(fā)隊列可以開啟多個線程钦铁,并且同時執(zhí)行多個任務。但是因為本身不能創(chuàng)建新線程才漆,只有當前線程這一個線程(同步任務不具備開啟新線程的能力)牛曹,所以也就不存在并發(fā)。而且當前線程只有等待當前隊列中正在執(zhí)行的任務執(zhí)行完畢之后醇滥,才能繼續(xù)接著執(zhí)行下面的操作(同步任務需要等待隊列的任務執(zhí)行結束)黎比。所以任務只能一個接一個按順序執(zhí)行,不能同時被執(zhí)行腺办。
  • 特點:在當前線程中執(zhí)行任務焰手,不會開啟新線程糟描,執(zhí)行完一個任務怀喉,再執(zhí)行下一個任務。
  • 異步執(zhí)行 + 并發(fā)隊列


    異步執(zhí)行 + 并發(fā)隊列.png

從上圖可以看出:

  • 除了當前線程(主線程)船响,系統(tǒng)又開啟了3個線程躬拢,并且任務是交替/同時執(zhí)行的。(異步執(zhí)行具備開啟新線程的能力见间。且并發(fā)隊列可開啟多個線程聊闯,同時執(zhí)行多個任務)。
  • 所有任務是在打印的syncConcurrent---begin和syncConcurrent---end之后才執(zhí)行的米诉。說明當前線程沒有等待菱蔬,而是直接開啟了新線程,在新線程中執(zhí)行任務(異步執(zhí)行不做等待,可以繼續(xù)執(zhí)行任務)拴泌。
  • 特點:可以開啟多個線程魏身,任務交替(同時)執(zhí)行。
  • 同步執(zhí)行 + 串行隊列


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

從上圖可以看出:

  • 所有任務都是在當前線程(主線程)中執(zhí)行的蚪腐,并沒有開啟新的線程(同步執(zhí)行不具備開啟新線程的能力)箭昵。
  • 所有任務都在打印的syncConcurrent---begin和syncConcurrent---end之間執(zhí)行(同步任務需要等待隊列的任務執(zhí)行結束)。
  • 任務是按順序執(zhí)行的(串行隊列每次只有一個任務被執(zhí)行回季,任務一個接一個按順序執(zhí)行)家制。
  • 特點:不會開啟新線程,在當前線程執(zhí)行任務泡一。任務是串行的颤殴,執(zhí)行完一個任務,再執(zhí)行下一個任務瘾杭。
  • 異步執(zhí)行 + 串行隊列


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

    從上圖可以看出:

  • 開啟了一條新線程(異步執(zhí)行具備開啟新線程的能力诅病,串行隊列只開啟一個線程)。
  • 所有任務是在打印的syncConcurrent---begin和syncConcurrent---end之后才開始執(zhí)行的(異步執(zhí)行不會做任何等待粥烁,可以繼續(xù)執(zhí)行任務)贤笆。
  • 任務是按順序執(zhí)行的(串行隊列每次只有一個任務被執(zhí)行,任務一個接一個按順序執(zhí)行)讨阻。
  • 特點:會開啟一條新線程芥永,但是因為任務是串行的,執(zhí)行完一個任務钝吮,再執(zhí)行下一個任務埋涧。

結尾

  • 以上純屬個人觀點,如有不對歡迎指出奇瘦。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末棘催,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子耳标,更是在濱河造成了極大的恐慌醇坝,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件次坡,死亡現(xiàn)場離奇詭異呼猪,居然都是意外死亡,警方通過查閱死者的電腦和手機砸琅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門宋距,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人症脂,你說我怎么就攤上這事谚赎∫В” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵壶唤,是天一觀的道長嘁傀。 經(jīng)常有香客問我,道長视粮,這世上最難降的妖魔是什么细办? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮蕾殴,結果婚禮上笑撞,老公的妹妹穿的比我還像新娘。我一直安慰自己钓觉,他們只是感情好茴肥,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著荡灾,像睡著了一般瓤狐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上批幌,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天础锐,我揣著相機與錄音,去河邊找鬼荧缘。 笑死皆警,一個胖子當著我的面吹牛,可吹牛的內容都是我干的截粗。 我是一名探鬼主播信姓,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼绸罗!你這毒婦竟也來了意推?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤珊蟀,失蹤者是張志新(化名)和其女友劉穎菊值,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體系洛,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡俊性,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年略步,在試婚紗的時候發(fā)現(xiàn)自己被綠了描扯。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡趟薄,死狀恐怖绽诚,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤恩够,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布卒落,位于F島的核電站,受9級特大地震影響蜂桶,放射性物質發(fā)生泄漏儡毕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一扑媚、第九天 我趴在偏房一處隱蔽的房頂上張望腰湾。 院中可真熱鬧,春花似錦疆股、人聲如沸费坊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽附井。三九已至,卻和暖如春两残,著一層夾襖步出監(jiān)牢的瞬間永毅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工人弓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留卷雕,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓票从,卻偏偏與公主長得像漫雕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子峰鄙,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內容