1. 進(jìn)程和線程的定義和關(guān)系
線程
- 線程是進(jìn)程的進(jìn)本執(zhí)行單元哪雕,一個進(jìn)程的所有任務(wù)都在線程中執(zhí)行
- 進(jìn)程中至少得有一個線程琼腔。程序啟動后默認(rèn)開啟一條線程抡诞,這條線程被叫做
主線程
或UI線程
進(jìn)程
- 進(jìn)程指系統(tǒng)中執(zhí)行的一個應(yīng)用程序
- 每個進(jìn)程之間是獨立的适刀,并且進(jìn)程運行在專用的且受保護的內(nèi)存空間中
Mac系統(tǒng)中活動監(jiān)視器
通過Mac系統(tǒng)中的“活動監(jiān)視器”能夠看到系統(tǒng)中開啟的進(jìn)程
- 圖中展示了當(dāng)前系統(tǒng)中開啟的
進(jìn)程
和進(jìn)程中開啟的線程
數(shù) - 有icon的說明有用戶界面秤朗;沒有icon是沒有用戶界面;
進(jìn)程和線程的關(guān)系
- 進(jìn)程中的線程共享本進(jìn)程中的地址空間笔喉。進(jìn)程之間是互相獨立的地址空間
- 進(jìn)程中的線程共享本進(jìn)程中的資源取视,如內(nèi)存、I/O常挚、CPU等作谭。進(jìn)程之間是資源獨立的。
通過以上的關(guān)系可以推到出:
- 進(jìn)程崩潰后奄毡,不會影響其他進(jìn)程折欠。但是線程崩潰后,整個進(jìn)程就崩潰了吼过。
- 進(jìn)程切換時锐秦,消耗資源大。所以涉及到頻繁切換時盗忱,使用線程要優(yōu)于進(jìn)程酱床。如果想要資源進(jìn)行并發(fā)操作時,只能使用線程趟佃。
- 進(jìn)程有一個程序入口扇谣,但是線程不能獨立執(zhí)行昧捷,必須在進(jìn)程(應(yīng)用程序)中。
- 線程是CPU基本調(diào)度單元罐寨,進(jìn)程不是靡挥。
- 線程沒有地址空間,線程是包含在進(jìn)程的地址空間中衩茸。
2. 多線程
優(yōu)點
- 能適當(dāng)提?程序的執(zhí)?效率
- 能適當(dāng)提?資源的利?率(CPU芹血,內(nèi)存)
- 線程上的任務(wù)執(zhí)?完成后,線程會?動銷毀
缺點
- 開啟線程需要占??定的內(nèi)存空間(默認(rèn)情況下楞慈,每?個線程都占 512 KB)
- 如果開啟?量的線程幔烛,會占??量的內(nèi)存空間,降低程序的性能
- 線程越多囊蓝,CPU 在調(diào)?線程上的開銷就越?
- 程序設(shè)計更加復(fù)雜饿悬,?如線程間的通信、多線程的數(shù)據(jù)共享
多線程技術(shù)方案
- pthread:一套通用的多線程API聚霜,適用于Unix狡恬、Linux、Windows等操作系統(tǒng)蝎宇。使用C語言弟劲,需要開發(fā)人員管理線程的生命周期。
- NSThread:更加面向?qū)ο罄呀妫褂肙C語言兔乞,也是需要開發(fā)人員管理線程的生命周期。
- GCD:蘋果提供的替代NSThread的方案凉唐,使用C語言實現(xiàn)庸追,不需要開發(fā)人員管理線程生命周期。
- NSOperation:基于GCD台囱,使用上更加面向?qū)ο蟮荨UZ言是OC,同樣不需要開發(fā)人員管理線程聲明周期簿训。
擴展 - C與OC橋接相關(guān)
- __bridge: 只做類型轉(zhuǎn)換咱娶,但是不修改對象內(nèi)存的管理權(quán)。
- __bridge_retained:也可以使用CFBridgingRetain强品,將OC對象轉(zhuǎn)換為Core Foundation對象豺总,同時將對象內(nèi)存的管理權(quán)交給開發(fā)人員,需要使用CFRelease或者相關(guān)方法進(jìn)行釋放择懂。
- __bridge_transfer:也可以使用CFBridgingRelease,將Core Foundation對象轉(zhuǎn)換為OC對象另玖,并將對象內(nèi)存的管理權(quán)交給ARC困曙。
3. 線程的生命周期
線程的生命周期中有的幾種狀態(tài):就緒表伦、運行、阻塞和死亡
慷丽。
- 新建線程T蹦哼,然后調(diào)用
start
,線程T進(jìn)入到就緒狀態(tài)要糊。等待CPU的調(diào)度纲熏。 - CPU調(diào)度線程池中可調(diào)用的線程,如果調(diào)用T锄俄,此時T是運行狀態(tài)局劲。如果調(diào)用了其他線程,那么T繼續(xù)保持就緒狀態(tài)奶赠。
- 如果代碼中調(diào)用了
Sleep
方法或者鎖相關(guān)的操作鱼填,T的狀態(tài)被調(diào)整成阻塞。Sleep
到時候或者獲取到同步鎖毅戈,T再回復(fù)成就緒狀態(tài)苹丸,等待CPU的調(diào)度。重復(fù)步驟2 - 運行完美結(jié)束后苇经,線程死亡赘理。
線程池
線程池就是線程的集合容器。容器里管理著線程的創(chuàng)建扇单、回收和重復(fù)利用線程商模。
使用線程池優(yōu)點:通過線程池,可以做到對線程的管理令花,比如重復(fù)利用已經(jīng)創(chuàng)建出來的線程阻桅,降低創(chuàng)建和銷毀線程時對性能的消耗。
大致的流程圖如下:
- 大致進(jìn)行了三個條件判斷:
- 條件1:判斷線程數(shù)量
- 條件2:判斷任務(wù)隊列
- 條件3:判斷是否有閑著的線程
- 先判斷條件1兼都,線程池中的線程數(shù)是否小于核心線程數(shù)嫂沉,不小于直接創(chuàng)建線程去執(zhí)行任務(wù)
- 如果條件1不滿足,條件2是去判斷任務(wù)隊列的狀況扮碧,如果任務(wù)隊列沒滿就將任務(wù)加入到隊列中趟章,等待線程去執(zhí)行。
- 條件3如果有閑著線程慎王,直接安排該線程去執(zhí)行任務(wù)
- 如果以上都不滿足蚓土,就要進(jìn)行飽和策略的處理了。
飽和策略
- AbortPolicy 直接拋出RejectedExecutionExeception異常來阻?系統(tǒng)正常運?赖淤。
- CallerRunsPolicy 將任務(wù)回退到調(diào)?者
- DisOldestPolicy 丟掉等待最久的任務(wù)
- DisCardPolicy 直接丟棄任務(wù)
這四點可以聯(lián)想一下工作中的場景蜀漆,如果當(dāng)前非常的忙,已經(jīng)是滿負(fù)荷的工作狀態(tài)咱旱,此時有一個新需求下來需要你做确丢,那么:
- AbortPolicy:整個人的心態(tài)崩了绷耍,沒法繼續(xù)工作。
- CallerRunsPolicy:把需求推回給發(fā)起者鲜侥,并告訴他褂始,現(xiàn)在沒有時間,等有時間再去做描函。
- DisOldestPolicy:做這個需求就得丟掉已經(jīng)排好的需求表中優(yōu)先級最低的任務(wù)崎苗,這樣才能按時完成全部工作。
- DisCardPolicy:直接說這個需求做不了舀寓。
4. 線程與runloop
- 線程與runloop是一一對應(yīng)的胆数。
- 開啟runloop,相當(dāng)于對線程是一種
被活
處理幅慌。線程執(zhí)行完任務(wù)后會進(jìn)入休眠狀態(tài),有任務(wù)了就會被喚醒去執(zhí)行任務(wù)轰豆。 - runloop在第一次獲取時被創(chuàng)建(類似懶加載的方式)胰伍,線程結(jié)束時被銷毀。
- 主線程的runloop酸休,是在程序啟動后默認(rèn)創(chuàng)建好的骂租。
- 子線程需要獲取一下(懶加載創(chuàng)建)才可以,比如在子線程使用定時器時斑司,如果不獲取runloop渗饮,定時器是不會發(fā)生回調(diào)的。