iOS底層系列22 -- 多線程基礎(chǔ)概念

進(jìn)程

  • 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序;
  • 每個(gè)進(jìn)程之間是相互獨(dú)立的,每個(gè)進(jìn)程均運(yùn)行在其專用的且受保護(hù)的內(nèi)存空間內(nèi);

線程

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

進(jìn)程與線程之間的關(guān)系

  • 進(jìn)程之間的地址空間是相互獨(dú)立,不能交叉訪問,同一個(gè)進(jìn)程內(nèi)的線程共享本進(jìn)程的地址空間;
  • 進(jìn)程之間的資源是相互獨(dú)立的,同一個(gè)進(jìn)程內(nèi)的線程共享本進(jìn)程的資源;
  • 兩個(gè)之間的關(guān)系就相當(dāng)于工廠與流水線的關(guān)系,工廠與工廠之間是相互獨(dú)立的,而工廠中的流水線是共享工廠的資源的,即進(jìn)程相當(dāng)于一個(gè)工廠,線程相當(dāng)于工廠中的一條流水線;

線程與RunLoop之間的關(guān)系

  • RunLoop與線程是一一對(duì)應(yīng)的,其保存在一個(gè)全局的字典當(dāng)中;
  • RunLoop是來管理線程的,當(dāng)線程的runloop被開啟后,線程會(huì)在執(zhí)行完任務(wù)后進(jìn)入休 眠狀態(tài),有了任務(wù)才會(huì)被喚醒去執(zhí)行任務(wù);
  • 對(duì)于主線程來說,RunLoop在程序一啟動(dòng)就默認(rèn)創(chuàng)建好了,在線程結(jié)束時(shí)被銷毀;
  • 對(duì)于子線程來說,RunLoop不會(huì)默認(rèn)創(chuàng)建, 其在第一次獲取時(shí)被創(chuàng)建,所以在子線程用定時(shí)器要注意:確保子線程的RunLoop被創(chuàng)建,不然定時(shí)器不會(huì)回調(diào);

多線程

  • iOS中的多線程同時(shí)執(zhí)行的本質(zhì)是: CPU在多個(gè)任務(wù)之間進(jìn)行快速的切換,由于CPU調(diào)度線程的時(shí)間足夠快,就造成了多線程的“同時(shí)”執(zhí)行的假象,讓我們認(rèn)為多個(gè)線程在同時(shí)執(zhí)行任務(wù),其中切換的時(shí)間間隔就是時(shí)間片;

多線程的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):
  • 能適當(dāng)提高應(yīng)用程序的執(zhí)行效率;
  • 能適當(dāng)提高系統(tǒ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ù)共享;

多線程的生命周期

線程的生命周期通常分為5個(gè)部分:創(chuàng)建 -- 就緒 -- 運(yùn)行 -- 阻塞 -- 死亡;其狀態(tài)之間的切換如下圖所示:

Snip20210319_208.png
  • 創(chuàng)建:即實(shí)例化線程對(duì)象;
  • 就緒:線程對(duì)象調(diào)用start方法,將線程對(duì)象加入可調(diào)度線程池,等待CPU的調(diào)用,即調(diào)用start方法,并不會(huì)立即執(zhí)行,而是進(jìn)入到就緒狀態(tài),需要等待一段時(shí)間,經(jīng)CPU調(diào)度后才執(zhí)行;
  • 運(yùn)行:CPU負(fù)責(zé)從可調(diào)度線程池中調(diào)度線程然后執(zhí)行,在線程執(zhí)行完成之前,其狀態(tài)可能會(huì)在就緒和運(yùn)行之間來回切換,這個(gè)變化是由CPU負(fù)責(zé),開發(fā)人員不能干預(yù);
  • 阻塞:當(dāng)滿足某個(gè)預(yù)定條件時(shí),可以讓線程休眠,即sleep,或者使用同步鎖,阻塞線程執(zhí)行,會(huì)將線程從可調(diào)度線程池中移除,當(dāng)線程解除sleep時(shí)/獲取到鎖,會(huì)重新將線程加入到可調(diào)度線程池中。下面關(guān)于休眠的時(shí)間設(shè)置,都是NSThread的;
  • 死亡:分為兩種情況
    • 正常死亡,即線程執(zhí)行完畢;
    • 非正常死亡,即當(dāng)滿足某個(gè)條件后,在線程內(nèi)部(或者主線程中)終止執(zhí)行(調(diào)用exit方法等退出)
  • 簡(jiǎn)要說明,就是處于運(yùn)行中的線程擁有一段可以執(zhí)行的時(shí)間(稱為時(shí)間片),如果時(shí)間片用盡,線程就會(huì)進(jìn)入就緒狀態(tài)隊(duì)列,如果時(shí)間片沒有用盡,且需要開始等待某事件,就會(huì)進(jìn)入阻塞狀態(tài)隊(duì)列;等待事件發(fā)生后,線程又會(huì)重新進(jìn)入就緒狀態(tài)隊(duì)列;
  • 每當(dāng)一個(gè)線程離開運(yùn)行,即執(zhí)行完畢或者強(qiáng)制退出后,會(huì)重新從就緒狀態(tài)隊(duì)列中選擇一個(gè)線程繼續(xù)執(zhí)行;
  • 線程的exit和cancel說明
    • exit:一旦強(qiáng)行終止線程,后續(xù)的所有代碼都不會(huì)執(zhí)行;
    • cancel:取消當(dāng)前線程,但是不能取消正在執(zhí)行的線程;

線程池的工作原理

  • 其工作原理如下圖所示:
Snip20210319_210.png
  • 首先線程池有兩個(gè)重要參數(shù)分別為:corePoolSize和maximumPoolSize;
  • corePoolSize表示核心線程池能創(chuàng)建核心線程的最大數(shù)量;
  • maximumPoolSize表示線程池能創(chuàng)建線程的最大數(shù)量;核心線程池包含在線程池中。
  • 【第一步】:當(dāng)有任務(wù)提交過來,首先判斷核心線程池是否已滿(corePoolSize)
    • 未滿,創(chuàng)建核心線程執(zhí)行任務(wù);
    • 已滿,進(jìn)入第二步;
  • 【第二步】:判斷工作隊(duì)列是否已滿
    • 未滿,將任務(wù)添加到工作隊(duì)列中;
    • 已滿,進(jìn)入第三步;
  • 【第三步】:判斷線程池是否已滿(maximumPoolSize)
    • 未滿:創(chuàng)建非核心線程執(zhí)行任務(wù);
    • 已滿:進(jìn)入第四步;
  • 【第四步】:執(zhí)行飽和策略,
  • 通常有以下四種飽和策略:
    • AbortPolicy(拋出一個(gè)異常,默認(rèn)的)
    • DiscardPolicy(新提交的任務(wù)直接被拋棄)
    • DiscardOldestPolicy(丟棄隊(duì)列里最老的任務(wù),將當(dāng)前這個(gè)任務(wù)繼續(xù)提交給線程池)
    • CallerRunsPolicy(交給線程池調(diào)用所在的線程進(jìn)行處理,即將某些任務(wù)回退到調(diào)用者)

iOS中多線程的實(shí)現(xiàn)方案

  • 主要有四種分別為:pthread,NSThreadGCD,NSOperation
Snip20210319_211.png
  • 下面通過代碼案例分別演示這四種多線程方案的實(shí)現(xiàn):
【pthread】
//線程回調(diào)函數(shù)
void * pthreadTest(){
    NSLog(@"===>%@", [NSThread currentThread]);
    return NULL;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    pthread_t threadId = NULL;
    //c字符串
    char *cString = "HelloCode";
    //創(chuàng)建一個(gè)字線程
    int result = pthread_create(&threadId,NULL,pthreadTest,cString);
    if (result == 0) {
        NSLog(@"pthread 創(chuàng)建成功");
    }else{
        NSLog(@"pthread 創(chuàng)建失敗");
    }
}
  • 需導(dǎo)入#import <pthread.h>
Snip20210319_212.png
【NSThread】
Snip20210319_214.png
【GCD】
Snip20210319_215.png
【NSOperation】
Snip20210319_217.png

線程安全問題

  • 同一時(shí)刻多條子線程共同訪問共享資源數(shù)據(jù),容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全問題,有以下兩種解決方案:
    • 互斥鎖(即同步鎖):@synchronized
    • 自旋鎖;
互斥鎖
  • 用于保護(hù)臨界區(qū),確保同一時(shí)間,只有一條線程能夠訪問執(zhí)行;
  • 加了互斥鎖的代碼,當(dāng)新線程訪問時(shí),如果發(fā)現(xiàn)有其他線程正在訪問共享資源,新線程就會(huì)進(jìn)入休眠狀態(tài);
  • 互斥鎖的鎖定范圍,應(yīng)該盡量小,鎖定范圍越大,效率越差;
  • 能夠加鎖的任意的NSObject對(duì)象;
  • 鎖對(duì)象一定要保證所有的線程都能夠訪問;
自旋鎖
  • 自旋鎖與互斥鎖類似,但它不是通過休眠使線程阻塞,而是在獲取鎖之前一直處于忙等(即原地打轉(zhuǎn),稱為自旋)阻塞狀態(tài);
  • 鎖持有的時(shí)間短,且線程不希望在重新調(diào)度上花太多成本時(shí),就需要使用自旋鎖,屬性修飾符atomic,本身就有一把自旋鎖;
  • 加入了自旋鎖,當(dāng)新線程訪問代碼時(shí),如果發(fā)現(xiàn)有其他線程正在鎖定代碼,新線程會(huì)用死循環(huán)的方法,一直等待鎖定的代碼執(zhí)行完成,即不停的嘗試執(zhí)行代碼,比較消耗性能;
【面試題】:自旋鎖 vs 互斥鎖
  • 相同點(diǎn):在同一時(shí)間,保證了只有一條線程訪問共享資源;
  • 不同點(diǎn):
    • 互斥鎖:發(fā)現(xiàn)其他線程執(zhí)行,當(dāng)前線程 休眠(即就緒狀態(tài)),進(jìn)入等待執(zhí)行,即掛起,一直等其他線程打開之后,然后喚醒執(zhí)行;
    • 自旋鎖:發(fā)現(xiàn)其他線程執(zhí)行,當(dāng)前線程一直詢問(即一直訪問),處于忙等狀態(tài),耗費(fèi)的性能比較高;
  • 場(chǎng)景:根據(jù)任務(wù)復(fù)雜度區(qū)分,使用不同的鎖,但判斷不全時(shí),更多是使用互斥鎖去處理
    當(dāng)前的任務(wù)狀態(tài)比較短小精悍時(shí),用自旋鎖,反之用互斥鎖;
最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • iOS 底層探索: 學(xué)習(xí)大綱 OC篇[/p/9d73ee7aae64] 前言 這篇開始探索多線程的底層原理,這篇主...
    歐德爾丶胡閱讀 292評(píng)論 0 2
  • 多線程,一直是解決內(nèi)存暴增方法的重點(diǎn),圖片、視頻、大量數(shù)據(jù)的的下載現(xiàn)在總結(jié)一下 基本概念 進(jìn)程:應(yīng)用程序的執(zhí)行實(shí)例...
    艷曉閱讀 308評(píng)論 0 0
  • 在開始之前,先理解以下幾點(diǎn)一、進(jìn)程和線程的區(qū)別和聯(lián)系:1、地址資源:進(jìn)程有自己的內(nèi)存地址,進(jìn)程內(nèi)的線程可以共享進(jìn)程...
    淡定的笨鳥閱讀 1,406評(píng)論 0 5
  • 本文源自本人的學(xué)習(xí)記錄整理與理解,其中參考閱讀了部分優(yōu)秀的博客和書籍,盡量以通俗簡(jiǎn)單的語句轉(zhuǎn)述。引用到的地方如有遺...
    水中的藍(lán)天閱讀 136評(píng)論 0 2
  • 推薦指數(shù): 6.0 書籍主旨關(guān)鍵詞:特權(quán)、焦點(diǎn)、注意力、語言聯(lián)想、情景聯(lián)想 觀點(diǎn): 1.統(tǒng)計(jì)學(xué)現(xiàn)在叫數(shù)據(jù)分析,社會(huì)...
    Jenaral閱讀 6,037評(píng)論 0 5

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