ios多線程詳解

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ios多線程詳解

一坚弱、前言

在ios中每個進(jìn)程啟動后都會建立一個主線程(UI進(jìn)程),這個線程是其他線程的父線程瓢喉。由于在ios中除了主線程,其他子線程都是獨(dú)立于Cocoa Touch的沪羔。多線程的實現(xiàn)有以下幾種方式:

NSThread:

(1)使用NSThread對象建立一個線程,非常方便翎碑。

(2)但是!使用NSThread管理多個線程非常困難,不推薦使用殖属。

GCD--Grand Central Dispatch:

(1)基于C語言的底層API颁糟。

(2)用block定義任務(wù),使用起來非常靈活方便铺董。

(3)提供了更多的控制能力以及操作隊列中所不能使用的底層函數(shù)统捶。

NSOperation/NSOperationQueue:

(1)是使用GCD實現(xiàn)的一套Object-C的API。

(2)是面向?qū)ο蟮木€程技術(shù)柄粹。

(3)提供了一些在GCD中不易實現(xiàn)的特性,如:限制最大并發(fā)數(shù)量、操作之間的依賴關(guān)系匆绣。

二驻右、線程與進(jìn)程

1.進(jìn)程

進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位,每一個進(jìn)程都有自己獨(dú)立的虛擬內(nèi)存空間。簡單來說,進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個應(yīng)用程序,每一個程序都是一個進(jìn)程,并且進(jìn)程之間是相互獨(dú)立的,每個進(jìn)程均運(yùn)行在其專業(yè)且受保護(hù)的內(nèi)存空間內(nèi)崎淳。

2.線程

是程序執(zhí)行流的最小單元堪夭,是系統(tǒng)獨(dú)立調(diào)度和分派CPU的基本單位。

一個進(jìn)程中至少有一條線程,即主線程。創(chuàng)建線程的目的就是為了開啟一條新的執(zhí)行路徑,運(yùn)行指定的代碼,與主線程中的代碼同時執(zhí)行森爽。

3.多線程

計算機(jī)同一個時間執(zhí)行多個線程,進(jìn)而提升整體處理性能恨豁。

原理:

(1)同一時間,CPU只能處理1條線程,只有一條線程在工作。

(2)多線程并發(fā)執(zhí)行,其實是CPU快速的在多條線程中切換(調(diào)度)爬迟。

(3)如果CPU調(diào)度線程的速度夠快橘蜜,就造成多線程同時執(zhí)行多假象。

優(yōu)點(diǎn):

(1)能適當(dāng)提高程序的執(zhí)行效率付呕。

(2)能適當(dāng)提高資源的利用率(CPU,內(nèi)存利用率)计福。

缺點(diǎn):

(1)開啟新線程需要占用一定的內(nèi)存空間(默認(rèn)情況下,主線程占1M,子線程占512K)。如果開啟大量的線程,會占用大量的內(nèi)存空間,降低程序的性能徽职。

(2)線程越多象颖,CPU在線程間切換(調(diào)度)上的開銷就越大。

注:主線程棧區(qū)的1M特別寶貴姆钉。不能殺掉一個線程!但可以暫停说订、休眠。


三潮瓶、NSThread的使用

1.線程的創(chuàng)建

NSThread創(chuàng)建線程有以下三種方法:

[NSThread detachNewThreadSelector:(nonnull SEL)> toTarget:(nonnull id) withObject:(nullable id)]

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

- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg

NSThread對象的常見屬性:

NSThread類方法:

(1)當(dāng)前線程:

int number = [NSThread currentThread];

number == 1 表示主線程陶冷,number != 1表示后臺線程

(2)阻塞方法:

休眠到指定時間

[NSThread sleepUntilDate:[NSDate date]];

休眠指定時長

[NSThread sleepForTimeInterval:4.5];

(3)其他類方法:

退出線程

[NSThread exit];

當(dāng)前線程是否為主線程

[NSThread isMainThread];

是否多線程

[NSThread isMultiThreaded];

返回主線程的對象

NSThread *mainThread = [NSThread mainThread];

2.線程的狀態(tài)

線程的狀態(tài)如下圖:

(1)新建:實例化對象

(2)就緒:向線程對象發(fā)送start消息,線程對象被加入"可調(diào)度線程池"等待CPU調(diào)度,detach方法和performSelectorInBackground方法會直接實例化一個線程對象并且加入"可調(diào)度線程池"筋讨。

(3)運(yùn)行:CPU負(fù)責(zé)調(diào)度"可調(diào)度線程池"中線程的執(zhí)行,線程完成執(zhí)行之前,其狀態(tài)可能在"就緒"和"運(yùn)行"之間切換埃叭。

(4)阻塞:當(dāng)滿足某個條件時,可以使用休眠或鎖阻塞線程執(zhí)行,方法有sleepForTimeInterval,sleepUntilDate,@synchronized(self)x線程鎖。線程進(jìn)入阻塞狀態(tài)下時,會被從"可調(diào)度線程池"中移出,CPU不再調(diào)度悉罕。

(5)死亡:死亡后線程對象的isFinished屬性為YES,如果是對線程發(fā)送cancel消息,線程對象的isCenceled屬性為YES,死亡后stackSize==0,內(nèi)存空間被釋放赤屋。

2.多線程的安全問題

多個線程訪問同一塊資源進(jìn)行讀寫,如果不加控制隨意訪問容易產(chǎn)生數(shù)據(jù)錯亂,從而引發(fā)數(shù)據(jù)安全問題。為了解決這一問題,就有了加鎖的概念壁袄。加鎖的原理就是當(dāng)有一個線程正在訪問資源進(jìn)行寫的時候类早,不允許其他線程再訪問該資源,只有當(dāng)該線程訪問結(jié)束后嗜逻,其他線程才按順序進(jìn)行訪問涩僻。對于讀取數(shù)據(jù),有些程序設(shè)計是允許多線程同時讀的,有些不允許。 UIKit中幾乎所有控件都不是線程安全的,因此需要在主線程中更新UI.

解決多線程安全問題:

(1)互斥鎖

?注意:鎖定1份代碼只用1把鎖栈顷,用多把鎖是無效的

@synchronized(鎖對象) { 需要鎖定的代碼? }

使用互斥鎖,在同一時間,只允許一條線程執(zhí)行鎖中的代碼逆日。因為互斥鎖的代價十分昂貴,所以鎖定的代碼范圍應(yīng)該盡可能吧小,只要鎖住資源讀寫部分的代碼即可萄凤。

(2)使用NSLock對象

(3)atomic加鎖

OC在定義屬性的時候有nonatomic和atomic兩種選擇室抽。

atomic:原子屬性,為setter方法加鎖(默認(rèn)就是atomic)靡努。線程安全,但需要消耗大量資源坪圾。

nonatomic:非原子屬性,不會為setter方法加鎖晓折。非線程安全,但效率高。

atomic加鎖原理:

ios開發(fā)的建議:

所有屬性都聲明nonatomic兽泄。

盡量避免多線程搶奪同一塊資源漓概。

盡量將加鎖、資源搶奪的業(yè)務(wù)邏輯交給服務(wù)器端處理病梢,減小移動端的壓力胃珍。


四、GCD的使用

GCD(Grand Central Dispatch)偉大的中央調(diào)度系統(tǒng),是蘋果為多核并行運(yùn)算提出的C語言并發(fā)技術(shù)框架飘千。GCD會自動利用更多的CPU內(nèi)核,會自動管理線程的生命周期(線程創(chuàng)建,調(diào)度任務(wù),線程銷毀),只需要告訴GCD想要如何執(zhí)行什么任務(wù),不需要編寫任何線程管理代碼堂鲜。

一些專業(yè)術(shù)語:

dispatch:調(diào)度/派遣

queue:隊列,用來存放任務(wù)的先進(jìn)先出(FIFO)的容器。

sync:同步函數(shù),只是在當(dāng)前線程中執(zhí)行任務(wù),不具備開啟新線程的能力护奈。

async:異步函數(shù),可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力缔莲。

concurrent:并發(fā),多個任務(wù)同時進(jìn)行。

串行:一個任務(wù)執(zhí)行完畢后,再執(zhí)行下一個任務(wù)霉旗。

1.GCD中的核心概念:

任務(wù): 任務(wù)就是要在線程中執(zhí)行的操作痴奏。我們將要執(zhí)行的代碼用block封裝好,然后將任務(wù)添加到隊列容器中,并指定任務(wù)的執(zhí)行方式。等待CPU從隊列中取出任務(wù)放到對應(yīng)的線程中執(zhí)行厌秒。

隊列

串行隊列:一次只調(diào)度一個任務(wù),一個任務(wù)完成后再調(diào)度下一個任務(wù)读拆。

并發(fā)隊列:可以同時調(diào)度多個任務(wù),調(diào)度任務(wù)的方式,取決于執(zhí)行任務(wù)的函數(shù),并發(fā)功能只有在異步函數(shù)下才有效。異步情況下鸵闪,開啟的新線程極限數(shù)量由GCD底層決定檐晕。

如果在MRC下需要使用dispatch_release釋放隊列:

主隊列:負(fù)責(zé)在主線程上調(diào)度任務(wù),如果在主線程上有任務(wù)執(zhí)行,會等待主線程空閑后再進(jìn)行調(diào)度。主隊列用于UI以及觸摸事件等的操作蚌讼。

全局并發(fā)隊列: 由蘋果API提供的,方便程序員使用多線程辟灰。

全局并發(fā)隊列的優(yōu)先級:

define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高優(yōu)先級

define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(rèn)(中)優(yōu)先級

注意,自定義隊列的優(yōu)先級都是默認(rèn)優(yōu)先級

define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低優(yōu)先級

define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后臺優(yōu)先級

全局并發(fā)隊列與并發(fā)隊列的區(qū)別:

(1)全局并發(fā)隊列沒有隊列名稱篡石。

(2)在MRC中,全局并發(fā)隊列不需要手動釋放芥喇。


執(zhí)行任務(wù)的函數(shù)

(1)同步函數(shù)(dispatch_sync)

任務(wù)被添加到隊列后,隊列中的任務(wù)一個接著一個執(zhí)行。

在主線程中,向主隊列添加同步任務(wù),會造成死鎖凰萨。

在其他線程中,向主隊列添加同步任務(wù),則會在主線程中同步執(zhí)行继控。

(2)異步函數(shù)(dispatch_async)


GCD的其他用法

(1)延時執(zhí)行

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

????// 2秒后異步執(zhí)行這里的代碼...

});

(2)一次性執(zhí)行

應(yīng)用場景:保證某段代碼在程序運(yùn)行過程中只被執(zhí)行一次,在單例模式中經(jīng)常被用到。

(3)調(diào)度組(隊列組)

五胖眷、NSOperation

NSOperation是蘋果推薦的并發(fā)技術(shù),它提供了一些GCD不是很好實現(xiàn)的功能武通。NSOperation是基于GCD的面向?qū)ο蟮腛C語言封裝。相比GCD,NSOperation的操作更簡單珊搀。NSOperation是一個抽象類厅须,不能直接使用,而是使用它的子類。蘋果為我們提供了其兩個子類:NSInvocationOperation,NSBlockOperation.以及繼承NSOperation的自定義子類食棕。

NSOperation的使用常常是配合NSOperationQueue來進(jìn)行的朗和。只要使用NSOperation子類創(chuàng)建的實例就能添加到NSOperationQueue中,一旦添加到隊列,操作就會自動異步執(zhí)行。如果沒有添加到隊列,而是使用start方法,則會在當(dāng)前線程中執(zhí)行簿晓。

(1)NSInvocationOperation

直接創(chuàng)建一個NSInvocationOperation對象,然后調(diào)用start方法會直接在主線程中執(zhí)行眶拉。

添加到NSOperationQueue中:

(2)NSBlockOperation

NSBlockOperation與NSInvocationOperation用法相同,只是創(chuàng)建的方式不同,它不需要去調(diào)用方法,而是直接使用代碼塊。這也使得NSBlockOperation比NSInvocationOperation更流行憔儿。

(3)NSOperationQueue的一些高級操作

NSOperationQueue的高級操作有:隊列的掛起,隊列的取消,添加操作的依賴關(guān)系和設(shè)置最大并發(fā)數(shù)量忆植。

最大并發(fā)數(shù):

線程的掛起:

取消隊列里的所有操作:

?六、三種線程技術(shù)比較

1.NSThread

優(yōu)點(diǎn):NSThread比其他兩個輕量級,使用簡單谒臼。

缺點(diǎn):需要管理自己的線程生命周期朝刊、加鎖、睡眠以及喚醒等蜈缤。

2.GCD

GCD是ios4.0以后才出現(xiàn)的并發(fā)技術(shù)

使用方式:將任務(wù)添加到隊列(串行/并行(全局))中,指定執(zhí)行任務(wù)的方法(同步函數(shù)sync,異步函數(shù)async)拾氓。

NSOperation無法做到的:延遲執(zhí)行,隊列組(NSOperation實現(xiàn)會比較復(fù)雜)。

3.NSOperation

NSOperation在ios2.0時就出現(xiàn)了(當(dāng)時不好用,后蘋果對其改造)

使用方式:將操作(異步執(zhí)行)添加到隊列(并發(fā)/全局)中底哥。

提供了GCD不好實現(xiàn)的功能:最大并發(fā)數(shù)咙鞍、取消所有任務(wù)、依賴關(guān)系趾徽。


GCD是比較底層的封裝续滋,我們知道較低層的代碼一般性能都是比較高的,相對于NSOperationQueue孵奶。所以追求性能疲酌,而功能夠用的話就可以考慮使用GCD。如果異步操作的過程需要更多的用戶交互和被UI顯示出來了袁,NSOperationQueue會是一個好選擇朗恳。如果任務(wù)之間沒有什么依賴關(guān)系,而是需要更高的并發(fā)能力早像,GCD則更有優(yōu)勢僻肖。

尾語:

高德納的教誨:“在大概97%的時間里,我們應(yīng)該忘記微小的性能提升卢鹦。過早優(yōu)化是萬惡之源臀脏。”只有Instruments顯示有真正的性能提升時才有必要用低級的GCD冀自。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末揉稚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子熬粗,更是在濱河造成了極大的恐慌搀玖,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,126評論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驻呐,死亡現(xiàn)場離奇詭異灌诅,居然都是意外死亡芳来,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評論 3 400
  • 文/潘曉璐 我一進(jìn)店門猜拾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來即舌,“玉大人,你說我怎么就攤上這事挎袜⊥缒簦” “怎么了?”我有些...
    開封第一講書人閱讀 169,941評論 0 366
  • 文/不壞的土叔 我叫張陵盯仪,是天一觀的道長紊搪。 經(jīng)常有香客問我,道長全景,這世上最難降的妖魔是什么耀石? 我笑而不...
    開封第一講書人閱讀 60,294評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮蚪燕,結(jié)果婚禮上娶牌,老公的妹妹穿的比我還像新娘。我一直安慰自己馆纳,他們只是感情好诗良,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,295評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鲁驶,像睡著了一般鉴裹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钥弯,一...
    開封第一講書人閱讀 52,874評論 1 314
  • 那天径荔,我揣著相機(jī)與錄音,去河邊找鬼脆霎。 笑死总处,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的睛蛛。 我是一名探鬼主播鹦马,決...
    沈念sama閱讀 41,285評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼忆肾!你這毒婦竟也來了荸频?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,249評論 0 277
  • 序言:老撾萬榮一對情侶失蹤客冈,失蹤者是張志新(化名)和其女友劉穎旭从,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,760評論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡和悦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,840評論 3 343
  • 正文 我和宋清朗相戀三年退疫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸽素。...
    茶點(diǎn)故事閱讀 40,973評論 1 354
  • 序言:一個原本活蹦亂跳的男人離奇死亡蹄咖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出付鹿,到底是詐尸還是另有隱情,我是刑警寧澤蚜迅,帶...
    沈念sama閱讀 36,631評論 5 351
  • 正文 年R本政府宣布舵匾,位于F島的核電站,受9級特大地震影響谁不,放射性物質(zhì)發(fā)生泄漏坐梯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,315評論 3 336
  • 文/蒙蒙 一刹帕、第九天 我趴在偏房一處隱蔽的房頂上張望吵血。 院中可真熱鬧,春花似錦偷溺、人聲如沸蹋辅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,797評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侦另。三九已至,卻和暖如春尉共,著一層夾襖步出監(jiān)牢的瞬間褒傅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,926評論 1 275
  • 我被黑心中介騙來泰國打工袄友, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留殿托,地道東北人。 一個月前我還...
    沈念sama閱讀 49,431評論 3 379
  • 正文 我出身青樓剧蚣,卻偏偏與公主長得像支竹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子券敌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,982評論 2 361

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

  • iOS多線程實踐中唾戚,常用的就是子線程執(zhí)行耗時操作,然后回到主線程刷新UI待诅。在iOS中每個進(jìn)程啟動后都會建立一個主線...
    jackyshan閱讀 1,454評論 2 12
  • 講多線程這個話題叹坦,就免不了先了解多線程相關(guān)的技術(shù)概念。本文涉及到的技術(shù)概念有CPU卑雁、進(jìn)程募书、線程绪囱、同異步、隊列等概念...
    jackyshan閱讀 3,784評論 2 26
  • 歡迎大家指出文章中需要改正或者需要補(bǔ)充的地方莹捡,我會及時更新鬼吵,非常感謝。 一. 多線程基礎(chǔ) 1. 進(jìn)程 進(jìn)程是指在系...
    xx_cc閱讀 7,198評論 11 70
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 29,427評論 8 265
  • iOS 多線程詳解 Slogan : 可能是最通俗易懂的 iOS多線程 詳細(xì)解析文章 1. 基礎(chǔ)概念 1.1 進(jìn)程...
    極客學(xué)偉閱讀 1,333評論 0 0