并發(fā) && 并行
多線程的同時執(zhí)行并非"并行", 而是"并發(fā)", "并發(fā)"無論從宏觀還是微觀上都是同時執(zhí)行的, 而"并行"宏觀上是同時執(zhí)行, 微觀上仍然是一個cpu的在多條線程上的來回切換.
多線程解決了什么問題?
從第一個問題可以看出, cpu(單核)在多條線程之間輪詢執(zhí)行的效率必然要低于單線程執(zhí)行. 在單核cpu的機器上單線程的效率是最高的. 所以多線程的出現(xiàn)并非是為了解決cpu的效率問題 (注意: 并非說多線程不能提高cpu的效率),而是為了解決"阻塞"問題, 如: task1 在 thread1 執(zhí)行需要10秒, task2 在 thread2 需要1秒, 人們不愿意等到 task1 執(zhí)行完成之后才能看到 task2 的執(zhí)行結(jié)果, 也就是不愿意 task1 阻塞 task2 的執(zhí)行. 可以說多線程是為了解決"阻塞"問題而生的.(多核cpu的問題涉及到硬件, 還不是很清楚, 不誤導大家了)
線程的串行
線程是進程的執(zhí)行單元/路徑
一個線程中執(zhí)行多個任務, 是按順序一個個執(zhí)行的
多線程的原理
CPU在各個線程中快速切換, 其調(diào)度線程的時間夠快, 就產(chǎn)生了多線程的"并發(fā)"執(zhí)行的假象
多線程優(yōu)缺點
優(yōu)點:
- 可以使任何需要及時響應的任務及時響應, 如用戶UI可以在進行其它工作的同時一直處于活動狀態(tài).
- 可以設置線程優(yōu)先級.
- 可以適當提高資源利用率, 如: 下載速度最大總共1m/s的網(wǎng)絡環(huán)境下, 單線程下載 task1 && task2, 如果因為某些原因?qū)е孪螺dtask1的速度只有100k/s, 那么下載完這2個任務的時間必然很長; 如果開啟2條線程下載, 下載速度就可能達到1m/s, 如此大大提高了帶寬的利用率.
缺點:
- 如果線程多每條線程被調(diào)度執(zhí)行的頻次會降低(線程的執(zhí)行效率低).
- 線程占用內(nèi)存, 主線程默認占1M, 子線程占用512k.
- 線程間通信和線程間數(shù)據(jù)共享, 資源搶奪造成程序的復雜性.
線程的狀態(tài)
- 可調(diào)度線程池概念
系統(tǒng)底層用于管理線程的一個"池子", 裝著所有可供系統(tǒng)調(diào)度的線程. - 線程的狀態(tài)
- new
為線程分配內(nèi)存空間 - runnable
線程進入可調(diào)度線程池 - running
線程有任務正在執(zhí)行 - blocked
線程阻塞, 被移除可調(diào)度線程池 - dead
線程死亡, 系統(tǒng)回收內(nèi)存
- new
線程安全問題
資源搶占
舉例: 如果一份文件需要張三和李四簽字, 可認為2人對應兩條線程, 若二人同時執(zhí)行簽字, 可能最后簽字結(jié)果是:張四李三, 李張三四等.
若要解決此問題, 必須保證文件在同一段時間被一個人占用, 另一個人要么先"睡會", 要么"干點別的", "睡會"和"干點別的"對應兩種線程鎖.-
鎖
- 同步鎖: @synchronized
用上面的例子, 張三在簽字的過程中, 把文件''鎖住'', 李四準備來簽, 看到文件被鎖, 會"睡等" - 自旋鎖 OSSpinLock
用上面的例子, 張三在簽字的過程中, 把文件''鎖住'', 李四準備來簽, 看到文件被鎖, 會"轉(zhuǎn)圈等".
- 同步鎖: @synchronized
兩種鎖的效率:
?對于同步鎖,如果資源已經(jīng)被占用,下一個調(diào)用者只能先進入睡眠狀態(tài)等待轧粟。但是自旋鎖不會引起調(diào)用者睡眠,如果自旋鎖已經(jīng)被別的執(zhí)行單元保持瘸爽,下一個調(diào)用者就一直循環(huán)在那里看是否該自旋鎖的保持者已經(jīng)釋放了鎖掖棉,"自旋"一詞就是因此而得名.
看上去 "自旋"會消耗大量資源, 效率更低. 實際情況是"睡"需要改變線程的狀態(tài), 會把線程從可調(diào)度線程池中取出, 從 runnable 狀態(tài)到blocked 狀態(tài). 而"自旋"在做一個空循環(huán), 不分配任何內(nèi)存空間, 相比與改變線程的狀態(tài)系統(tǒng)消耗的資源會少一些.
- 原子屬性
atomic :消耗較多資源, 相對線程安全
nonatomic:非線程安全
線程間通信
在一個進程中, 線程往往不是孤立存在的, 多線程經(jīng)常需要相互通信:
- 一個線程傳遞數(shù)據(jù)給另一個線程
- 在一個線程中執(zhí)行完特定的任務后, 轉(zhuǎn)到另一個線程繼續(xù)執(zhí)行
iOS中多線程的實現(xiàn)方案
技術(shù) | 簡介 | 語言 | 生命周期 |
---|---|---|---|
pthread | 跨平臺Unix Linux Windows | C | 需要管理 |
NSThread | 面向?qū)ο?可直接操作線程對象 | OC | 需要管理 |
GCD | 中樞調(diào)度系統(tǒng)(在隊列中調(diào)度任務到相應線程) | C | 系統(tǒng)管理 |
NSOperation | 對GCD的封裝, 面向?qū)ο?/td> | OC | 系統(tǒng)管理 |
- pthread
基本過時, 很少能看見iOS項目中有使用
NSThread
iOS中 NSThread 多用于的判斷線程編號, 是否處于主線程等-
GCD
- 自動管理線程的生命周期 (創(chuàng)建線程, 調(diào)度任務), C,JAVA中需要關(guān)注
- 核心: 任務添加隊列, 任務的取出遵循隊列FIFO原則
在 GCD 中,一個同步函數(shù)只在完成了它預定的任務后才返回赫粥。
一個異步函數(shù)龟劲,剛好相反胃夏,會立即返回,預定的任務會完成但不會等它完成.因此昌跌,一個異步函數(shù) . 不會阻塞當前線程去執(zhí)行下一個函數(shù).
-
NSOperation
- 對GCD的封裝, 是GCD的進一步抽象, NSOperation封裝了需要執(zhí)行的操作和執(zhí)行操作所需的數(shù)據(jù),讓程序員面向?qū)ο箝_發(fā).
- NSOperation本身是個抽象類,必須用其子類(系統(tǒng)提供子類, 也可以自定義子類)
- NSOperation 封裝了一些方法, 方便設置依賴, 方便取消操作, 方便判斷當前操作的狀態(tài)等.
- 建議較為底層的, 公用的多線程模塊使用NSOperation, 其效率雖比GCD略低, 不過其面向?qū)ο笠约澳軐崿F(xiàn)繼承的優(yōu)點就足以讓程序員們?nèi)ナ褂?