常常聽到這樣的問題 "你在處理多線程的時候 遇到過什麼問題 或者說 你使用過多線程嗎 如何操做的"算法
具體 我也沒聽過 別人是怎麼回答的,我也沒太想好怎樣回答纔算全面,今天利用工做空餘時間好好系統學一下,從如下幾個角度學習數據庫
1 理論編程
2 舉例子運用多線程
3 實際開發注意要點併發
一 理論app
1 線程和進程async
a 通常運行一個程序就是一個進程. 一個程序至少有一個進程,一個進程至少有一個線程函數
b 線程,是進程的一部分,一個沒有線程的進程能夠被看做是單線程的 (相對進程而言,線程是一個更加接近於執行體的概念)性能
c 進程能夠建立線程 也能夠建立進程 學習
d 線程由進程管理, 線程之間 線程和父進程之間(建立線程的進程)共享內存變量 (須要策略實現)
e 進程之間通常不能夠直接共享內存變量,須要一些進程間的控制共享內存變量
2 iOS 多線程編程技術(這裏主講GCD)
NSThread NSOperation GCD
(1) NSThread
優勢: 使用起來比 其餘兩個更輕量級
缺點:須要本身管理線程的生命週期,線程同步. 線程同步的加鎖會又必定的系統開銷
(2)NSOperation
優勢:無需關心線程管理,數據同步.關鍵是操做執行操做.
相關類:抽象類 NSInvocationOperation 和 NSBlockOperation
建立NSOperation子類對象,把對象添加到NSOperationqueue隊列裏執行
(3)GCD (grand central dispatch)
iOS4後開始使用,是代替以上兩種多線程方法的強大技術,GCD中FIFO隊列稱爲 dispatch queue
dispatch queue :
a 串行隊列: serial 隊列 隊裏任務 是一個一個地執行
dispatch_queue_t queue = dispatch_queue_create("com.xxx.serialQueue",DISPATCH_QUEUE_SERIAL);// 本身建立一個串行隊列
b 並行隊列:concurrent 隊列 一般任務會併發的執行
dispatch_queue_t queue = dispatch_queue_create("com.xxx.concurrentQueue",DISPATCH_QUEUE_CONCURRENT);// 本身建立一個並行隊列
c 全局隊列 : 系統級別的,直接拿來用,是一種併發隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
d 主隊列 :一個應用程序對應惟一一個主隊列,也是系統級別,直接拿來用,多線程開發使用主隊列更新UI. 是一種串行隊列
dispatch_queue_t queue = dispatch_get_main_queue();
二 舉例運用
dispatch queue
#define global_queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define main_queue dispatch_get_main_queue()
(1)dispatch_async
耗時懂得操做,數據處理,IO讀取數據庫什麼的 在另外一個線程中處理,而後通知主線程更新UI
經常使用方法:
dispatch_async(global_queue, ^{ //耗時間性能的處理放在這 dispatch_sync(main_queue, ^{ //主線程更新UI }); });
(2)dispatch_group_async
能夠實現監聽一組任務是否完成, 完成後獲得通知再執行其餘操做
經常使用方法舉例:下載 5張圖片(或者說有五個獨立數據請求),下載完了更新UI (都請求完成後執行其餘操做)
- (void)fun { // 建立一個組 dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, global_queue, ^{ //開啓一個任務1 }); dispatch_group_async(group, global_queue, ^{ // 開啓一個任務2 });
//開啓一個任務3
//開啓一個任務4
//開啓一個任務5
dispatch_group_notify(group, main_queue, ^{
// 等group中的全部任務都執行完畢, 再回到主線程執行其餘操做 }); }
(3)dispathch_barrier_async(柵欄函數)
void dispatch_barrier_async ( dispatch_queue_t queue, dispatch_block_t block );
參數 queue: 將barrier添加到那個隊列
block: barrier block 代碼塊
"在它前面的的任務執行後它才執行,在它後面的任務須要等它執行完成後才能執行".
使用狀況是和並行隊列一塊兒使用,"同dispatch_queue_create函數生成的concurrent Dispatch Queue隊列一塊兒使用", 這個queue 必定是 本身建立的 併發隊列,若是是 使用全局併發隊列或者是一個串行隊列,那麼這個函數等同於dispatch_async函數.
使用舉例:
- (void)barrier { dispatch_queue_t queue = dispatch_queue_create("myConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);//這個queue 必定是 本身建立的 併發隊列,若是是 使用全局併發隊列或者是一個串行隊列,那麼這個函數等同於dispatch_async函數. dispatch_async(queue, ^{ NSLog(@"任務1"); }); dispatch_async(queue, ^{ NSLog(@"任務2"); }); dispatch_barrier_async(queue, ^{ NSLog(@"barrier"); }); dispatch_async(queue, ^{ NSLog(@"任務3"); }); dispatch_async(queue, ^{ NSLog(@"任務4"); }); }
打印結果
任務1
任務2 (1 和 2 併發 順序不定)
barrier
任務3
任務4 (3 和 4 併發 順序不定)
(4)dispatch_apply
執行N次的某一個代碼片斷
dispatch_apply(5, global_queue, ^(size_t index){ //此處任務執行5次 });
三 實際開發注意要點
重點是關注多線程死鎖問題,和正確選擇多線程策略
關於死鎖,主要參考大學操做系統課程標配講解:
死鎖緣由
(1)資源競爭 資源分配不當
(2)系統資源不足
(3)進程運行推動順序不合適
死鎖條件:
(1)互斥:進程在某一時間內獨佔資源
(2)請求與保持:進程已經擁有當前資源,可是又申請新資源
(3)不可剝奪: 進程的資源沒使用完 就不能夠強行從資源佔有者處爭奪資源
(4)循環等待 : 出現閉環
死鎖預防:(破壞上述四個必要條件的一個或者幾個)
(1)破壞上述四個必要條件的一個或者幾個 來防止死鎖產生
(2)鴕鳥算法,發生錯誤機率極小 可忽略
(3)仔細檢查對資源的動態分配狀況,來預防死鎖
(4)檢測死鎖而且恢復
(5)避免死鎖的一個通用的經驗法則是:當幾個線程都要訪問共享資源A、B、C時,保證使每一個線程都按照一樣的順序去訪問它們,好比都先訪問A,在訪問B和C。這樣不會產生閉環.
參考:
https://developer.apple.com/reference/dispatch#//apple_ref/c/func/dispatch_barrier_async