iOS 多線程之基礎(chǔ)

在開(kāi)始之前,先理解以下幾點(diǎn)
一、進(jìn)程和線程的區(qū)別和聯(lián)系:
1、地址資源:進(jìn)程有自己的內(nèi)存地址,進(jìn)程內(nèi)的線程可以共享進(jìn)程的內(nèi)存地址
2、資源分配和調(diào)度:進(jìn)程是系統(tǒng)進(jìn)行資源分配和擁有的基本單位,同一個(gè)進(jìn)程內(nèi)的線程可共享進(jìn)程的資源
3、線程是CPU調(diào)度的基本單位。
4、二者都可以并發(fā)執(zhí)行
二、多線程的意義
優(yōu)點(diǎn):
1、提高資源(CPU和內(nèi)存)利用率
2、提高程序的執(zhí)行效率
3、線程上的任務(wù)執(zhí)行完后,線程會(huì)自動(dòng)銷毀
缺點(diǎn):
1、開(kāi)辟線程需要占用一定的內(nèi)存空間(默認(rèn)每個(gè)線程占用512kb)
2、線程越多,CPU調(diào)度的開(kāi)銷越大
三、多線程原理
多線程的并發(fā)執(zhí)行其實(shí)并不是同時(shí)執(zhí)行,而是CPU在不同的線程間頻繁切換,達(dá)到的“偽同時(shí)”效果。這是由于每一個(gè)分得CPU的任務(wù)都會(huì)有一個(gè)時(shí)間片,它執(zhí)行完時(shí)間片的時(shí)間,CPU就不屬于它們了,要等待再次分配。

拋出問(wèn)題

問(wèn)題1、主線程是做什么的?
答:主線程是iOS程序運(yùn)行后開(kāi)辟的第一個(gè)線程,也叫UI線程,用來(lái)顯示/刷新UI界面和處理UI事件。
問(wèn)題2、UI為什么要在主線程更新?
答:蘋(píng)果為了性能考慮,UIKit不是線程安全的,試想如果UI可以在子線程更新,那么如果有多個(gè)線程同時(shí)修改某個(gè)資源時(shí)將會(huì)出現(xiàn)很多莫名其妙的錯(cuò)誤。
問(wèn)題3、能不能把渲染放到子線程?怎么渲染
遺留問(wèn)題。

線程和Runloop的關(guān)系

1、Runloop和線程是一一對(duì)應(yīng)的關(guān)系
2、Runloop是來(lái)管理線程的,當(dāng)線程的runloop被開(kāi)啟后,線程執(zhí)行完任務(wù)會(huì)休眠,等下次有任務(wù)時(shí)再執(zhí)行任務(wù)。
3、線程在第一次創(chuàng)建是被開(kāi)啟,在線程結(jié)束時(shí)銷毀
3、Runloop在子線程中默認(rèn)不開(kāi)啟,需要手動(dòng)操作才能開(kāi)啟。注意NSTImer

線程池工作原理

系統(tǒng)中的線程屬于寶貴資源,合理運(yùn)用線程池,可以減少創(chuàng)建和銷毀線程的次數(shù),使得每個(gè)線程可以重復(fù)利用。

  • corePoolSize:線程池基本大小(核心線程數(shù)量)
  • maximumPoolSize:線程池允許的最大線程數(shù)
  • keepAliveTime:當(dāng)線程池的線程數(shù)量大于corePoolSize時(shí),空閑線程的最大存活時(shí)間
  • workQueue:存放任務(wù)的工作隊(duì)列
  • handler:超出線程范圍和隊(duì)列容量的任務(wù)的處理程序

線程池的工作流程:當(dāng)提交一個(gè)任務(wù)時(shí),線程池會(huì)做出如下判斷
1、如果正在運(yùn)行的線程數(shù)量小于corePoolSize,馬上創(chuàng)建線程執(zhí)行任務(wù)。
2、如果正在運(yùn)行的線程數(shù)量大于等于corePoolSize,則放入工作隊(duì)列中。
3、如果不巧,工作隊(duì)列也滿了,而且正在運(yùn)行的線程數(shù)量小于maximumPoolSize,那么還是要?jiǎng)?chuàng)建線程立刻運(yùn)行這個(gè)任務(wù)。
4、如果正在運(yùn)行的線程數(shù)量大于等于maximumPoolSize,則交給飽和策略處理。
如圖所示

線程池工作原理 .png

當(dāng)線程池的線程執(zhí)行完任務(wù)以后,會(huì)從工作隊(duì)列取下一個(gè)任務(wù)執(zhí)行。
當(dāng)一個(gè)線程空閑,且正在運(yùn)行的線程數(shù)大于corePoolSize,則計(jì)時(shí)超過(guò)keepAliveTime線程就會(huì)被kill掉,所以當(dāng)線程池中任務(wù)都完成后,它最終會(huì)縮小到corePoolSize大小。

飽和策略

當(dāng)任務(wù)提交線程池失敗時(shí),即當(dāng)前提交的任務(wù)數(shù)超過(guò)maxmumPoolSizeworkQueue之和時(shí),就會(huì)交給飽和策略處理。
飽和策略有四種,AbortPolicy、CallerRunsPolicyDiscardPolicy、DiscardOldestPolicy

策略 Description
AbortPolicy 中止策略,屬于默認(rèn)的飽和策略,該策略將拋出未檢查的RejectedExecutionException。調(diào)用者可以捕獲這個(gè)異常,然后根據(jù)需要編寫(xiě)自己的處理代碼。
DiscardPolicy 拋棄策略,當(dāng)新提交的任務(wù)無(wú)法保存到隊(duì)列中等待執(zhí)行時(shí),“拋棄(Discard)”策略會(huì)悄悄拋棄該任務(wù)。
DiscardOldestPolicy 拋棄下一個(gè)將被執(zhí)行的任務(wù),然后嘗試重新提交新的任務(wù)。(如果工作隊(duì)列是一個(gè)優(yōu)先隊(duì)列,那么“拋棄最舊的”策略將導(dǎo)致拋棄優(yōu)先級(jí)最高的任務(wù),因此最好不要將“拋棄最舊的”飽和策略和優(yōu)先隊(duì)列放在一起使用。)
CallerRunsPolicy 調(diào)用者策略,策略實(shí)現(xiàn)了一種調(diào)度機(jī)制,該策略既不會(huì)拋棄任務(wù),也不會(huì)拋出異常,而是將某些任務(wù)回退到調(diào)用者,從而降低新任務(wù)的流量。它不會(huì)在線程池的某個(gè)線程中執(zhí)行新提交的任務(wù),而是在一個(gè)調(diào)用了execute的線程中執(zhí)行該任務(wù)。如果采用有界隊(duì)列和“調(diào)用者運(yùn)行”飽和策略,當(dāng)線程池中的所有線程都被占用,并且工作隊(duì)列被填滿后,下一個(gè)任務(wù)會(huì)在調(diào)用execute時(shí)在主線程中執(zhí)行。由于執(zhí)行任務(wù)需要一定的時(shí)間,因此主線程至少在一段時(shí)間內(nèi)不能提交任何任務(wù),從而使得工作者線程有時(shí)間來(lái)處理完正在執(zhí)行的任務(wù)。在此期間,主線程不會(huì)調(diào)用accept,因此到達(dá)的請(qǐng)求將被保存在TCP層的隊(duì)列中而不是在應(yīng)用程序的隊(duì)列中。如果持續(xù)過(guò)載,那么TCP層將最終發(fā)現(xiàn)它的請(qǐng)求隊(duì)列被填滿,因此同樣會(huì)開(kāi)始拋棄請(qǐng)求。當(dāng)服務(wù)器過(guò)載時(shí),這種過(guò)載情況會(huì)逐漸向外蔓延開(kāi)來(lái)——從線程池到工作隊(duì)列到應(yīng)用程序再到TCP層,最終達(dá)到客戶端,導(dǎo)致服務(wù)器在高負(fù)載下實(shí)現(xiàn)一種平緩的性能降低。

線程的生命周期

線程生命周期的每一步如下所示:

  • 1、新建:實(shí)例化線程對(duì)象
  • 2、就緒:調(diào)用start將線程加入可調(diào)度線程池,等待CPU調(diào)度(分配時(shí)間片)。
  • 3、運(yùn)行:CPU從可調(diào)度線程池中分配時(shí)間片給線程,線程在未執(zhí)行完畢情況下可能會(huì)在就緒運(yùn)行之間不斷切換,程序員無(wú)法干預(yù)。
  • 4、阻塞:線程有時(shí)會(huì)因?yàn)橥?、鎖、sleep等方式阻塞。
  • 5、死亡:分為正常死亡(線程結(jié)束)和非正常死亡(線程終止)。
線程生命周期.png
多線程的四種技術(shù)方案

多線程有四種技術(shù)方案分別是pthread、NSThread、GCD和NSOperation,如下圖所示


多線程的幾種方式

我們一般使用比較多的是GCD,因?yàn)殚_(kāi)發(fā)者只需要告訴 GCD 想要執(zhí)行什么任務(wù),不需要編寫(xiě)任何線程管理代碼,但這也是GCD的不夠靈活的地方,我們無(wú)法監(jiān)控線程的各個(gè)狀態(tài),這也是很多大框架中使用NSOperation的原因,NSOperation相比GCD更加靈活,開(kāi)發(fā)者可以通過(guò)KVO監(jiān)測(cè)Operation的狀態(tài),自定義NSOperation等。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • iOS多線程編程 基本知識(shí) 1. 進(jìn)程(process) 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序,就是一段程序的執(zhí)...
    陵無(wú)山閱讀 6,346評(píng)論 1 14
  • 又來(lái)到了一個(gè)老生常談的問(wèn)題,應(yīng)用層軟件開(kāi)發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢? 今天就這個(gè)問(wèn)題開(kāi)始,來(lái)談?wù)劜?..
    tangsl閱讀 4,322評(píng)論 0 23
  • 多線程 在iOS開(kāi)發(fā)中為提高程序的運(yùn)行效率會(huì)將比較耗時(shí)的操作放在子線程中執(zhí)行,iOS系統(tǒng)進(jìn)程默認(rèn)啟動(dòng)一個(gè)主線程,用...
    郭豪豪閱讀 2,721評(píng)論 0 4
  • 首先了解單線程:一、單線程的應(yīng)用,整個(gè)應(yīng)用中只有一個(gè)順序執(zhí)行流,當(dāng)執(zhí)行流在執(zhí)行某個(gè)耗時(shí)的操作,或者不能立即完成的任...
    甘哲157閱讀 701評(píng)論 1 8
  • 走親串友深山行, 山雨欲來(lái)風(fēng)云涌。 驚嘆遇上鬼天氣, 頻遭數(shù)襲黑旋風(fēng)。 急返失足溺水里, 有幸得救乃郎中。 平時(shí)功...
    太陽(yáng)哥月亮妹閱讀 426評(píng)論 3 16

友情鏈接更多精彩內(nèi)容