1. 進程和線程的定義和關系
線程
- 線程是進程的進本執行單元,一個進程的所有任務都在線程中執行
- 進程中至少得有一個線程。程序啟動后默認開啟一條線程,這條線程被叫做
主線程
或UI線程
進程
- 進程指系統中執行的一個應用程序
- 每個進程之間是獨立的,并且進程運行在專用的且受保護的內存空間中
Mac系統中活動監視器
通過Mac系統中的“活動監視器”能夠看到系統中開啟的進程
- 圖中展示了當前系統中開啟的
進程
和進程中開啟的線程
數 - 有icon的說明有用戶界面;沒有icon是沒有用戶界面;
進程和線程的關系
- 進程中的線程共享本進程中的地址空間。進程之間是互相獨立的地址空間
- 進程中的線程共享本進程中的資源,如內存、I/O、CPU等。進程之間是資源獨立的。
通過以上的關系可以推到出:
- 進程崩潰后,不會影響其他進程。但是線程崩潰后,整個進程就崩潰了。
- 進程切換時,消耗資源大。所以涉及到頻繁切換時,使用線程要優于進程。如果想要資源進行并發操作時,只能使用線程。
- 進程有一個程序入口,但是線程不能獨立執行,必須在進程(應用程序)中。
- 線程是CPU基本調度單元,進程不是。
- 線程沒有地址空間,線程是包含在進程的地址空間中。
2. 多線程
優點
- 能適當提?程序的執?效率
- 能適當提?資源的利?率(CPU,內存)
- 線程上的任務執?完成后,線程會?動銷毀
缺點
- 開啟線程需要占??定的內存空間(默認情況下,每?個線程都占 512 KB)
- 如果開啟?量的線程,會占??量的內存空間,降低程序的性能
- 線程越多,CPU 在調?線程上的開銷就越?
- 程序設計更加復雜,?如線程間的通信、多線程的數據共享
多線程技術方案
- pthread:一套通用的多線程API,適用于Unix、Linux、Windows等操作系統。使用C語言,需要開發人員管理線程的生命周期。
- NSThread:更加面向對象,使用OC語言,也是需要開發人員管理線程的生命周期。
- GCD:蘋果提供的替代NSThread的方案,使用C語言實現,不需要開發人員管理線程生命周期。
- NSOperation:基于GCD,使用上更加面向對象。語言是OC,同樣不需要開發人員管理線程聲明周期。
擴展 - C與OC橋接相關
- __bridge: 只做類型轉換,但是不修改對象內存的管理權。
- __bridge_retained:也可以使用CFBridgingRetain,將OC對象轉換為Core Foundation對象,同時將對象內存的管理權交給開發人員,需要使用CFRelease或者相關方法進行釋放。
- __bridge_transfer:也可以使用CFBridgingRelease,將Core Foundation對象轉換為OC對象,并將對象內存的管理權交給ARC。
3. 線程的生命周期
線程的生命周期中有的幾種狀態:就緒、運行、阻塞和死亡
。
- 新建線程T,然后調用
start
,線程T進入到就緒狀態。等待CPU的調度。 - CPU調度線程池中可調用的線程,如果調用T,此時T是運行狀態。如果調用了其他線程,那么T繼續保持就緒狀態。
- 如果代碼中調用了
Sleep
方法或者鎖相關的操作,T的狀態被調整成阻塞。Sleep
到時候或者獲取到同步鎖,T再回復成就緒狀態,等待CPU的調度。重復步驟2 - 運行完美結束后,線程死亡。
線程池
線程池就是線程的集合容器。容器里管理著線程的創建、回收和重復利用線程。
使用線程池優點:通過線程池,可以做到對線程的管理,比如重復利用已經創建出來的線程,降低創建和銷毀線程時對性能的消耗。
大致的流程圖如下:
- 大致進行了三個條件判斷:
- 條件1:判斷線程數量
- 條件2:判斷任務隊列
- 條件3:判斷是否有閑著的線程
- 先判斷條件1,線程池中的線程數是否小于核心線程數,不小于直接創建線程去執行任務
- 如果條件1不滿足,條件2是去判斷任務隊列的狀況,如果任務隊列沒滿就將任務加入到隊列中,等待線程去執行。
- 條件3如果有閑著線程,直接安排該線程去執行任務
- 如果以上都不滿足,就要進行飽和策略的處理了。
飽和策略
- AbortPolicy 直接拋出RejectedExecutionExeception異常來阻?系統正常運?。
- CallerRunsPolicy 將任務回退到調?者
- DisOldestPolicy 丟掉等待最久的任務
- DisCardPolicy 直接丟棄任務
這四點可以聯想一下工作中的場景,如果當前非常的忙,已經是滿負荷的工作狀態,此時有一個新需求下來需要你做,那么:
- AbortPolicy:整個人的心態崩了,沒法繼續工作。
- CallerRunsPolicy:把需求推回給發起者,并告訴他,現在沒有時間,等有時間再去做。
- DisOldestPolicy:做這個需求就得丟掉已經排好的需求表中優先級最低的任務,這樣才能按時完成全部工作。
- DisCardPolicy:直接說這個需求做不了。
4. 線程與runloop
- 線程與runloop是一一對應的。
- 開啟runloop,相當于對線程是一種
保活
處理。線程執行完任務后會進入休眠狀態,有任務了就會被喚醒去執行任務。 - runloop在第一次獲取時被創建(類似懶加載的方式),線程結束時被銷毀。
- 主線程的runloop,是在程序啟動后默認創建好的。
- 子線程需要獲取一下(懶加載創建)才可以,比如在子線程使用定時器時,如果不獲取runloop,定時器是不會發生回調的。