本系列全部開發文檔翻譯連接地址:iOS7開發-Apple蘋果iPhone開發Xcode官方文檔翻譯PDF下載地址(2013年12月29日更新版)html
多線程
技術博客http://www.cnblogs.com/ChenYilong/ 新浪微博http://weibo.com/luohanchenyilong
多線程的應用
• 耗時操做,例如網絡圖片、視頻、歌曲、書籍等資源下載 • 遊戲中的聲音播放
多線程示意圖
• 充分發揮多核處理器的優點,併發(同時執行) 執行任務讓系統運行的更快、更流暢
進程與線程概念
• 一個運行的程序就是一個進程或者叫作一個任務
• 一個進程至少包含一個線程,線程是程序的執行流
• iOS程序啓動時,在建立一個進程的同時, 會開始運行一個線程,該 線程被稱爲主線程
• 主線程是其餘線程最終的父線程,全部界面的顯示操做必須在主線程 進行
• 後臺線程沒法更新UI界面和響應用戶點擊事件
• 系統中的每個進程都有本身獨立的虛擬內存空間,而同一個進程中
的多個線程則共用進程的內存空間
• 每建立一個新的線程,都會消耗必定內存和CPU時間
• 當多個線程對同一個資源出現爭奪的時候須要注意線程安全問題
多線程的優點與難點
• 優點
– 充分發揮多核處理器優點,將不一樣線程任務分配給不一樣的處
理器,真正進入「並行運算」狀態
– 將耗時、輪詢或者併發需求高等任務分配到其餘線程執行, 並由主線程負責統一更新界面會使得應用程序更加流暢,用 戶體驗更好
– 當硬件處理器的數量增長,程序會運行更快,而無需作任何 調整
• 難點
– 共享資源的「爭奪」
– 多線程是爲了同步完成多項任務,不是爲了提升運行效率, 而是爲了經過提升資源使用效率來提升系統的總體性能
多線程使用注意事項
• 線程使用不是無節制的– iOS中的主線程的堆棧大小是1M
– 從第二個線程開始都是512KB
– 這些數值不能經過編譯器開關或線程API函數更改
• 只有主線程有直接修改UI的能力
iOS的三種多線程技術 程序員
1.
NSThread
每一個
NSThread
對象對應一個線程,量級較輕(真正的多線
程)
2.
如下兩點是蘋果專門開發的「併發」技術,使得程序員能夠再也不去 關心線程的具體使用問題
.1.
NSOperation/NSOperationQueue
面向對象的線程技術
.2.
GCD —— Grand Central Dispatch
(派發)
是基於
C
語言的框架,
能夠充分利用多
核
,是蘋果推薦使用的多線程技術
.
以上這三種編程方式從上到下,抽象度層次是從低到高的,
抽象度越高 的使用越簡單,也是
Apple
最推薦使用的
。可是就目前而言,
iOS
的開發者, 須要瞭解三種多線程技術的基本使用過程。由於不少框架技術分別使用 了不一樣多線程技術。
三種多線程技術的對比
•
NSThread:
–
優勢:
NSThread
比其餘兩個輕量級,
使用簡單
–
缺點:
須要本身管理線程的生命週期、線程同步、加鎖、睡眠以 及喚醒等
。線程同步
對數據的加鎖
會有必定的系統開銷
•
NSOperation
:
–
不須要關心線程管理,數據同步的事情,能夠把精力放在本身需
要執行的操做上
–
NSOperation
是面向對象的
•
GCD
:
–
Grand Central Dispatch
是
由蘋果開發的一個多核編程的解決方案
。
iOS4.0+
才能使用,是替代
NSThread
,
NSOperation
的高效和強大 的技術
//轉載請註明出處--本文永久連接:http://www.cnblogs.com/ChenYilong/p/3494799.html
–
GCD
是基於
C
語言的
演練(
1
)
NSObject
的多線程方法
——
準備
.1.
建立一個耗時較長的操做
.2.
建立一個耗時較短的操做
.3.
在界面中心放置兩個按鈕,分別調用 這兩個任務
.4.
使用
[NSThread currentThread]
分別打 印各個任務所在的線程
.5.
運行觀察效果
•
提示:
•
NSLog
是一個至關耗時的操做 在應用 程序正式發佈前,必定記住須要對應用 中的
NSLog
方法進行處理
•
不管使用哪種多線程技術,都可以使 用
[NSThread currentThread]
查看當前任 務所在線程
NSObject
的多線程方法
——
後臺線程
- (
void
)performSelectorInBackground:(
SEL
)aSelector
withObject:(
id
)arg
•
一般,因爲線程管理相對比較繁瑣,而不少耗時的任務又沒法知道其準 確的完成時間,所以可使用
performSelectorInBackground
方法 直接新建一個後臺線程,並將選擇器指定的任務在後臺線程執行,而無 需關心具體的
NSThread
對象
•
提示:
–
performSelectorInBackground
方法自己是在主線程中執行的,
而選擇器指定的方法是在後臺線程中進行的
–
使用
performSelectorInBackground
方法調用的任務能夠更新
UI
界面
–
在大型交互式遊戲中,一般使用此方法在後臺線程播放音效
@autoreleasepool
•
內存管理對於多線程很是重要
•
Objective-C
能夠憑藉
@autoreleasepool
使用內存資源,並須要時回 收資源
•
每一個線程都須要有
@autoreleasepool
,不然可能會出現內存泄漏
NSObject
的多線程方法
——
主線程
- (
void
)performSelectorOnMainThread:(
SEL
)aSelector
withObject:(
id
)arg waitUntilDone:(
BOOL
)wait;
•
若是要更新
UI
界面,能夠在後臺線程中調用
performSelectorOnMainThread
方法
•
提示
:儘管使用
performSelectorInBackground
方法調用的任務 能夠更新
UI
界面,可是在實際開發中,涉及到
UI
界面的更新操做,還 是要使用
performSelectorOnMainThread
方法,以免沒必要要的 麻煩
NSObject
的多線程小結
•
開啓後臺執行任務的方法
-
(
void
)performSelectorInBackground:(
SEL
)aSelector withObject:(
id
)arg
•
在後臺線程中通知主線程執行任務的方法
–
(
void
)performSelectorOnMainThread:(
SEL
)aSelector
withObject:(
id
)arg waitUntilDone:(
BOOL
)wait;
•
獲取線程信息
[
NSThread
currentThread
];
•
線程休眠
[
NSThread
sleepForTimeInterval
:
1.0f
];
•
特色:
–
使用簡單,量級輕
–
不能控制線程的執行順序
NSThread
•
建立線程方法:
1.
+ (
void
)detachNewThreadSelector:(
SEL
)
selector
toTarget:(
id
)
target
withObject:(
id
)
argument
;
2.
- (
id
)initWithTarget:(
id
)
target
selector: (
SEL
)
selector
object:(
id
)
argument
;
•
參數說明:
–
selector
:
線程執行的方法
,只能有一個參數,不能有返回值
–
target
:
selector
消息發送的對象
–
argument
:傳輸給
target
的惟一參數,也能夠是
nil
NSThread
演練
——
加載圖片
•
detachNewThreadSelector
方法會直接啓動線程方法
•
initWithTarget
須要調用
start
方法纔可以啓動線程方 法
NSOperation & NSOperationQueue
•
NSOperation
的兩個子類
1.
NSInvocationOperation 2.
NSBlockOperation
•
工做原理:
1.
用
NSOperation
封裝要執行的操做
2.
將建立好的
NSOperation
對象放
NSOperationQueue
中
3.
啓動
OperationQueue
開始新的線程執行隊列中的操做
•
注意事項:
.1.
使用多線程時一般須要控制線程的併發數
,由於線程會消耗系統資源,
同時運行的線程過多,系統會變慢
.
.2.
使用如下方法能夠控制併發的線程數量:
-
(
void
)setMaxConcurrentOperationCount:(
NSInteger
)cnt;
//轉載請註明出處--本文永久連接:http://www.cnblogs.com/ChenYilong/p/3494799.html
NSOperation
演練
——
加載圖片
.1.
不能直接使用
NSOperation
.2.
定義完操做後,
將添加到操做隊列中
,便可啓動異步操做,不然操 做任務仍然在主線程中執行
.3.
使用
NSBlockOperation
更加簡單直接
.4.
使用
setMaxConcurrentOperationCount
能夠限制併發操做數
量,下降系統開銷
.5.
使用
addDependency
能夠創建操做之間的依賴關係,設定操做的執行 順序
GCD
•
GCD
是基於
C
語言的框架
•
工做原理
:
–
讓程序平行排隊的特定任務,根據可用的處理資源,
安排它們在
任何可用的處理器上執行任務
–
要執行的任務能夠是一個函數或者一個
block
–
底層是經過線程實現的,不過程序員能夠沒必要關注實現的細節
–
GCD
中的
FIFO
隊列稱爲
dispatch queue
,能夠保證先進來的任務先 獲得執行
–
dispatch_notify
能夠實現
監聽一組任務是否完成
,完成後得 到通知
•
GCD
隊列
:
1.
全局隊列:
全部添加到主隊列中的任務都是併發執行的
2.
串行隊列:
全部添加到串行隊列中的任務都是順序執行的
3.
主隊列:
全部添加到主隊列中的任務都是在主線程中執行的
獲取隊列的方法
•
全局隊列(可能會開啓多條線程)
dispatch_queue_t
queue =
dispatch_get_global_queue
(
DISPATCH_QUEUE_PRIORITY_DEFAULT
,
0
);
•
串行隊列(只可能會開啓一條線程)
dispatch_queue_t
queue =
dispatch_queue_create
(
"myQueue"
,
DISPATCH_QUEUE_SERIAL
);
•
主隊列
dispatch_get_main_queue
();
GCD
任務的執行方式
——
同步
&
異步
•
異步操做
–
dispatch_async
在其餘線程執行任務,會開啓新的線程
–
異步方法沒法肯定任務的執行順序
•
同步操做
–
dispatch_sync
在當前在當前線程執行任務,不開啓新的線程
–
同步操做與隊列無關
–
同步方法會依次執行,可以決定任務的執行順序
–
更新界面
UI
時,最好使用同步方法
GCD
演練
——
加載圖片
•
GCD
的優勢:
–
充分利用多核
–
全部的多線程代碼集中在一塊兒,便於維護
–
GCD
中無需使用
@autoreleasepool
–
若是要順序執行,可使用
dispatch_sync
同步方法
–
dispatch_async
沒法肯定任務的執行順序
單例模型
•
目的
:
–
保證在內存中永遠只有類的單個實例
•
創建方法
:
1.
聲明一個靜態成員變量,記錄惟一實例
2.
重寫
allocWithZone
方法
allocWithZone
方法是對象分配內存空間時,最終會調用的方法, 重寫該方法,保證只會分配一個內存空間
3.
創建
sharedXXX
類方法,便於其餘類訪問
互斥鎖的目的,一次只讓一個線程訪問資源,從而達到資源的線程安全。編程
在
iPhone
開發中,一般要儘可能避免使用互斥鎖!
多線程演練
——
賣票
•
系統預設
–
共有
30
張票能夠銷售(
開發時能夠少一些,專一實現)
–
售票工做由兩個線程併發進行
–
沒有可出售票據時,線程工做中止
–
兩個線程的執行時間不一樣,模擬售票人員效率不一樣
–
使用一個多行文本框公告售票進度(主線程更新
UI
)
•
線程工做安排
–
主線程:負責更新
UI
–
線程
1
:模擬第
1
名賣票員
–
線程
2
:模擬第
2
名賣票員
–
兩個線程
幾乎
同時開始賣票
單線程賣票流程圖
多線程賣票示意圖
演練準備
——
更新
UI
方法,由主線程調用
// 1.
取出當前的文本
NSMutableString
*str = [
NSMutableString
stringWithString
: [
self
.
textView
text
]];
// 2.
追加文本
[str
appendFormat
:
@"%@\n"
, text];
// 3.
設置文本
[
self
.
textView
setText
:str];
// 4.
選中最末位置,實現自動滾動效果
NSRange
range =
NSMakeRange
(str.
length
-
1
,
1
); [
self
.
textView
scrollRangeToVisible
:range];
//轉載請註明出處--本文永久連接:http://www.cnblogs.com/ChenYilong/p/3494799.html
賣票演練
•
資源爭奪
–
僅使用單例模式沒法解決資源爭奪問題
–
使用互斥鎖
@synchronized
能夠保證多個線程不會使用同一代碼塊,並且比
NSLock
具備更好的性能
–
爲了保證屬性安全,被爭奪資源的屬性應該設置爲原子屬性
atomic
•
GCD
–
GCD
的多線程更加靈活、方便
–
dispatch_group_notify
能夠監聽一組任務是否完成
。這個方法頗有用,好比
你執行三個下載任務,當三個任務都下載完成後,才通知界面說已經完成
–
若是不須要監聽一組任務,能夠直接使用
dispatch_async
方法
•
NSOperation
–
更新界面時使用
[[
NSOperationQueue
mainQueue
]
addOperationWithBlock
:
方法
•
NSThread
–
涉及到線程調度問題,平常開發不建議使用
三種多線程技術的流程對比
關於
iOS
多線程使用的建議
•
掌握大綱內容便可,關於多個線程之間的調度問題,待往後熟練後可
以自行學習,目前不建議再繼續深刻
•
關於多線程必須記住的三個要點
–
只能在主線程中更新
UI
–
共享數據爭奪的處理
,互斥鎖
@synchronized
(
self
)
和原子屬
性
atomic
–
不要使用多種多線程技術去爭奪同一個資源
•
使用多線程是爲了處理併發操做的。若是有可能,咱們不要去作搶資 源的事情 互斥鎖的代價至關的昂貴
//轉載請註明出處--本文永久連接:http://www.cnblogs.com/ChenYilong/p/3494799.html 安全
https://www.evernote.com/shard/s227/sh/8e2008b3-1d9e-42e6-b193-551e6dbe7440/e39f99e835da159ac641e28679c3c00b網絡