標籤:
一. 名詞解釋:
1. 進程和線程
進程是指在系統中正在啟動並執行一個應用程式.每個進程之間都是獨立的,每個進程均運行在期專用而且受到保護的記憶體空間中.
線程是指一個進程想要執行任務,就必須要有線程.線程是進程的基本單元,一個進程的所有任務都線上程中進行.
2. 具體的對多線程的描述請看 文頂頂大神的部落格.http://www.cnblogs.com/wendingding/p/3805088.html
二. 隊列
/** 隊列: 用於存放任務.分為:串列隊列和並行隊列. 1. 串列隊列: 放到串列隊列中的任務,GCD會FIFO(先進先出)的取出來一個,執行一個,然後取出來下一個,這樣一個一個的執行. 2. 並行隊列: 放到並行隊列中的任務,GCD也會FIFO的取出來,但不同的是,他取出來一個任務就會放到別的線程中,然後取出來一個又放到另一個線程中.由於取的動作很快,可以忽略不計,看起來,所有的任務都是一起執行的.不過需要注意,GCD會根據系統資源控制並行的數量.所以任務很多也不會然所有的任務都執行. */
三. 任務
/** 任務: 有兩種執行方式,同步執行和非同步執行.區別是是否會建立新的線程. 1. 同步執行(sync): 會阻塞當前的線程並等待Block執行完畢,然後當前線程才會繼續往下運行. 2. 非同步執行(async): 當前線程會直接往下執行,它不會阻塞當前線程. */
四.
/** 擷取主線程 1. 所有的重新整理UI介面的任務都要在主線程執行. 2. 將消耗時間的任務放在別的線程中出來,盡量不要在主線程中處理. */ dispatch_queue_t main_queue = dispatch_get_main_queue(); NSLog(@"main_queue:\n %@",main_queue); /** 自己建立的隊列 dispatch_queue_create 參數1: 第一個參數是標識符.用於DEBUG的時候標誌唯一的隊列,可以為空白. 參數2: 第二個參數用來表示建立的隊列是串列的還是並行的.傳入DISPATCH_QUEUE_SERIAL或者NULL表示建立的是串列隊列.傳入DISPATCH_QUEUE_CONCURRENT表示建立的並行隊列. (SERIAL--> serial連續的/CONCURRENT--> concurrent,並發的,一致的) */ // 建立串列隊列 dispatch_queue_t serialQueue = dispatch_queue_create(nil, NULL); NSLog(@"serialQueue:\n %@",serialQueue); // 建立並行隊列: 這應該是唯一一個並行隊列,只要是並行任務一般都加入到這個隊列 dispatch_queue_t concurrentQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT); NSLog(@"concurrentQueue:\n %@",concurrentQueue); // 建立任務 /** 同步任務 (sync) 1. 不會另外開闢線程. */ dispatch_sync( serialQueue, ^{ for (int i = 0; i < 10000; i ++) { NSLog(@"同步任務: \n%@",[NSThread currentThread]); } }); /** 同步任務 (async) 1. 會另外開闢線程. */ dispatch_async(serialQueue, ^{ NSLog(@"非同步任務: %@",[NSThread currentThread]); });
五. 例子介紹
NSLog(@"之前==> %@",[NSThread currentThread]); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"sync==> %@",[NSThread currentThread]); }); NSLog(@"之後==> %@",[NSThread currentThread]); /** 解釋 1. 只會列印第一句:之前==> <NSThread: 0x7fe66b700610>{number = 1, name = main} ,然後主線程就卡死了,你可以在介面上放一個按鈕,你就會發現點不了了。 2. 列印完第一句,dispatch_sync(因為是一個同步任務,會阻塞當前的線程)會阻塞當前的主線程,然後把Block中的任務放到main_queue中,main_queue中的任務會被取出來放到主線程中執行,但主線程種鴿時候已經被阻塞了,所以Block種鴿的任務就不能完成,它不完成,dispatch_sync就會一直阻塞主線程.導致主線程一直卡死.這就是死結現象. */
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL); NSLog(@"輸出1.之前==> %@",[NSThread currentThread]); dispatch_async(queue, ^{ NSLog(@"輸出2.sync之前==> %@",[NSThread currentThread]); dispatch_sync(queue, ^{ NSLog(@"輸出3.sync==> %@",[NSThread currentThread]); }); NSLog(@"輸出4.sync之後==> %@",[NSThread currentThread]); }); NSLog(@"輸出5.之後==> %@",[NSThread currentThread]); /** 解釋 1. 當前線程為預設的主線程 2. 輸出結果為,輸出1,輸出5和輸出2 執行了輸出.輸出3和輸出4沒有被執行. 3. 按照執行順序分析. (1)我們建立的隊列queue是一個串列隊列(DISPATCH_QUEUE_SERIAL).串列隊列的特點是,所持有的任務會取出一個執行一個.當前任務沒有執行完,下一個任務不會被執行. (2)列印出輸出1. (3)在queue隊列中開啟了一個非同步任務(async).非同步任務的特點是,當前的線程不會被阻塞.所以有了兩條線程,一條是主線程中執行輸出5.另一條是在新開闢的queue線程中執行輸出2. (4)在開闢的queue線程中,又執行了一個同步的任務(sync),同步任務的特點是執行一個任務會阻塞當前的線程.當前的線程是queue,已經被阻塞了.又要求它去執行下一個任務.就造成了死結現象.所以 sync 所在的線程被卡死了,輸出3和輸出4自然就不會列印了. */
六.隊列組可以將很多隊列添加到一個組裡,這樣做的好處是,當這個組裡所有的任務都執行完了,隊列組會通過一個方法通知我們。
//1. 建立隊列組 dispatch_group_t group = dispatch_group_create(); //2. 建立隊列 dispatch_get_global_queue 會擷取一個全域隊列,我們姑且理解為系統為我們開啟的一些全域線程。我們用priority指定隊列的優先順序,而flag作為保留欄位備用(一般為0)。 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //3. 多次使用隊列中的方法執行任務,只有非同步任務 //3.1 執行三次迴圈 dispatch_group_async(group, queue, ^{ for (int i = 0; i < 3; i ++) { NSLog(@"group-01 - %@",[NSThread currentThread]); } }); //3.2 主隊列執行8次迴圈 dispatch_group_async(group, dispatch_get_main_queue(), ^{ for (int i = 0; i < 8; i ++) { NSLog(@"group-02 - %@",[NSThread currentThread]); } }); //3.3 執行5次迴圈 dispatch_group_async(group, queue, ^{ for (int i = 0; i < 5; i ++) { NSLog(@"group-03 - %@",[NSThread currentThread]); } }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"完成 - %@",[NSThread currentThread]); });
iOS-多線程-GCD