多線程

線程和進(jìn)程的定義

線程是進(jìn)程的基本執(zhí)行單元,一個(gè)進(jìn)程的所有任務(wù)都在線程中執(zhí)行
進(jìn)程要想執(zhí)行任務(wù),必須得有線程,進(jìn)程至少要有一條線程
程序啟動(dòng)默認(rèn)會(huì)開啟一條線程,這條線程被稱為主線程或UI線程

進(jìn)程是指系統(tǒng)正在運(yùn)行的一個(gè)應(yīng)用程序
每個(gè)進(jìn)程之間是獨(dú)立的,每個(gè)進(jìn)程均運(yùn)行在其專用的且受保護(hù)的內(nèi)存空間內(nèi)
通過“活動(dòng)監(jiān)視器”可以查看Mac系統(tǒng)中所開啟的進(jìn)程

地址空間:同一進(jìn)程的線程共享本進(jìn)程的地址空間,而進(jìn)程之間則是獨(dú)立的地址空間
資源擁有:同一進(jìn)程的線程共享本進(jìn)程的資源如內(nèi)存I/O、CPU等,但是進(jìn)程之間的資源是獨(dú)立的。

1:一個(gè)進(jìn)程崩潰后,在保護(hù)模式下不會(huì)對(duì)其他進(jìn)程產(chǎn)生影響,但是一個(gè)線程奔潰整個(gè)進(jìn)程都死掉。所以多進(jìn)程要比多線程健壯。
2:進(jìn)程切換時(shí),消耗的資源大,效率高。所以涉及到頻繁的切換時(shí),使用線程要好于進(jìn)程。同樣如果要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程不能用進(jìn)程。
3.執(zhí)行過程:每個(gè)獨(dú)立的進(jìn)程有一個(gè)程序運(yùn)行的入口、順序執(zhí)行序列和程序入口。但是線程不能獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。
4.線程是處理器調(diào)度的基本單位,但是進(jìn)程不是。
5.線程沒有地址空間,線程包含在進(jìn)程地址空間中

多線程的意義

優(yōu)點(diǎn)
能適當(dāng)提高程序的執(zhí)行效率
能適當(dāng)提高資源的利用率(CPU,內(nèi)存)
線程上的任務(wù)執(zhí)行完成后,線程會(huì)自動(dòng)銷毀

缺點(diǎn)
開啟線程需要占用一定的內(nèi)存空間(默認(rèn)情況下,每一個(gè)線程都占512KB)
如果開啟大量的線程,會(huì)占用大量的內(nèi)存空間,降低程序的性能
線程越多,CPU在調(diào)用線程上的開銷就越大
程序設(shè)計(jì)更加復(fù)雜,比如線程間的通信、多線程的數(shù)據(jù)共享

時(shí)間片的概念:CPU在多個(gè)任務(wù)之間進(jìn)行快速的切換,這個(gè)時(shí)間間隔就是時(shí)間片

(單核CPU)同一時(shí)間,CPU只能處理1個(gè)線程
換言之,同一時(shí)間只有1個(gè)線程在執(zhí)行
多線程同時(shí)執(zhí)行:
是CPU快速的在多個(gè)線程之間的切換
CPU調(diào)度線程的時(shí)間足夠快,就造成了多線程的“同時(shí)”執(zhí)行的效果
如果線程數(shù)非常多
CPU會(huì)在N個(gè)線程之間切換,消耗大量的CPU資源
每個(gè)線程被調(diào)度的次數(shù)會(huì)降低,線程的執(zhí)行效率降低

多線程技術(shù)方案

C與OC的橋接

__bridge只做類型轉(zhuǎn)換,但是不修改對(duì)象(內(nèi)存)管理權(quán);
__bridge_retained(也可以使用CFBridgingRetain)將Objective-C的對(duì)象轉(zhuǎn)換為Core Foundation的對(duì)象,同時(shí)將對(duì)象(內(nèi)存)的管理權(quán)交給我們,后續(xù)需要使用CFRelease或者相關(guān)方法來釋放對(duì)象;
__bridge_transfer(也可以使用CFBridgingRelease)將 Core Foundation的對(duì)象轉(zhuǎn)換為Objective-C的對(duì)象,同時(shí)將對(duì)象(內(nèi)存)的管理權(quán)交給ARC。

線程的生命周期

線程池

飽和策略

AbortPolicy直接拋出RejectedExecutionExeception異常來阻止系統(tǒng)正常運(yùn)行
CallerRunsPolicy將任務(wù)回退到調(diào)用者
DisOldestPolicy丟掉等待最久的任務(wù)
DisCardPolicy直接丟棄任務(wù)

這四種拒絕策略均實(shí)現(xiàn)的RejectedExecutionHandler接口

互斥鎖

互斥鎖小結(jié)
保證鎖內(nèi)的代碼,同一時(shí)間,只有一條線程能夠執(zhí)行!
互斥鎖的鎖定范圍,應(yīng)該盡量小,鎖定范圍越大,效率越差!

互斥鎖的參數(shù)
能夠加鎖的任意NSObject對(duì)象
注意:鎖對(duì)象一定要保證所有的線程都能夠訪問
如果代碼中只有一個(gè)地方需要加鎖,大多使用self,這樣可以避免單獨(dú)再創(chuàng)建一個(gè)鎖對(duì)象

atomic與nonatomic的區(qū)別
atomic原子屬性(線程安全),針對(duì)多線程設(shè)計(jì)的,默認(rèn)值
保證同一時(shí)間只有一個(gè)線程能夠?qū)懭耄ǖ峭粋€(gè)時(shí)間多個(gè)線程都可以取值)
atomic本身就有一把鎖(自旋鎖)
單寫多讀:單個(gè)線程寫入,多個(gè)線程可以讀取
atomic:線程安全,需要消耗大量的資源
nonatomic:非線程安全,適合內(nèi)存小的移動(dòng)設(shè)備

iOS開發(fā)的建議
所有的屬性聲明為nonatomic
盡量避免多線程搶奪同一塊資源
盡量將加鎖、資源搶奪的業(yè)務(wù)邏輯交給服務(wù)器端處理,減小移動(dòng)客戶端的壓力

線程和Runloop的關(guān)系
runloop與線程是一一對(duì)應(yīng)的,一個(gè)runloop對(duì)應(yīng)一個(gè)核心的線程,為什么說核心的線程,是因?yàn)閞unloop是可以嵌套的,但是核心的線程只能有一個(gè),他們的關(guān)系保存在一個(gè)全局的字典里。
runloop是來管理線程的,當(dāng)線程的runloop被開啟后,線程會(huì)在執(zhí)行完任務(wù)后進(jìn)入休眠狀態(tài),有了任務(wù)就會(huì)被喚醒去執(zhí)行任務(wù)。
runloop在第一次獲取時(shí)被創(chuàng)建,在線程結(jié)束時(shí)被銷毀。
對(duì)主線程來說,runloop在程序一啟動(dòng)就默認(rèn)創(chuàng)建好了。
對(duì)于子線程來說,runloop是懶加載的,只有當(dāng)我們使用的時(shí)候才會(huì)被創(chuàng)建,所以在子線程用定時(shí)器時(shí)要注意:確保子線程的runloop被創(chuàng)建,不然定時(shí)器不會(huì)回調(diào)。

最后編輯于
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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