要了解多線程首先要知道什麼是進程,什麼是進程?算法
#pragma mark - 串行(一個接一個,排隊跑步,保持隊形)隊列 - (void)gcdDemo1 { // 將操做放在隊列中// 使用串行隊列,的異步任務很是很是很是有用!新建子線程是有開銷的,不能無休止新建線程 // 建立一個串行隊列 dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL); // 非ARC開發時,千萬別忘記release // dispatch_release(q);for (int i = 0; i < 10; ++i) { // 異步任務,併發執行,可是若是在穿行隊列中,仍然會依次順序執行 dispatch_async(q, ^{ // [NSThread currentThread] 能夠在開發中,跟蹤當前線程 // num = 1,表示主線程 // num = 2,表示第2個子線程。。。 NSLog(@"%@ %d", [NSThread currentThread], i); }); } }
上面的代碼是建立一個串行隊列,並添加10個任務到隊列中,運行這個方法時,你會看到控制檯輸出的順序是從1到10的,證實這10個任務是一個執行完在執行另外一個,而且是按照添加順序來的網絡
再來看一下併發隊列裏面添加10個任務會怎樣多線程
dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcd2", DISPATCH_QUEUE_CONCURRENT); for (int i = 0; i < 10; ++i) { // 同步任務順序執行 dispatch_async(q, ^{ NSLog(@"%@ %d", [NSThread currentThread], i); }); }
從控制檯的打印信息來看,你會看到打印是無序的,因此能夠驗證,並行隊列不是(((按照順序 && 執行完一個才執行一個的)))併發
可是前四個打印中確定有(0,1,2,3){若是開啓了四個線程的話}中的一個,由於並行隊列裏面前四個是0,1,2,3,因此前四個打印中,確定會有其中一個異步
同時咱們注意到上面向隊列裏面添加任務時候都是用的dispatch_async異步執行,那若是用dispatch_sync同步執行會是什麼結果呢?async
dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcd2", DISPATCH_QUEUE_CONCURRENT); for (int i = 0; i < 10; ++i) { // 同步任務順序執行 dispatch_sync(q, ^{ NSLog(@"%@ %d", [NSThread currentThread], i); }); }
根據控制檯的輸出咱們能夠看到,輸出是按順序來的,而且打印出來的Tread信息都是主線程,證實上面任務的執行都是在主線程上完成的函數
(由於因此的任務都按順序從隊列裏面出來,而且處理的線程就一個,因此會挨個執行)性能
由於這個代碼所在的線程就是主線程,因此sync就在本線程中執行(不開闢新線程)spa
一樣的,咱們來看一下串行隊列裏的同步任務執行結果:線程
dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL); for (int i = 0; i < 10; ++i) { // 同步任務順序執行 dispatch_sync(q, ^{ NSLog(@"%@ %d", [NSThread currentThread], i); }); }
你會看到跟上面同樣的結果
下面咱們再來看一下並行隊列時的一些問題
- (void)gcdDemo2 { dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcd2", DISPATCH_QUEUE_CONCURRENT); for (int i = 0; i < 10; ++i) { // 異步任務(第一批任務) dispatch_async(q, ^{ // [NSThread currentThread] 能夠在開發中,跟蹤當前線程 // num = 1,表示主線程 // num = 2,表示第2個子線程。。。 NSLog(@"%@ %d", [NSThread currentThread], i); }); } for (int i = 0; i < 10; ++i) { // 同步任務順序執行(第二批任務) dispatch_sync(q, ^{ NSLog(@"%@ %dkkkkkk", [NSThread currentThread], i); }); } }
你會看到第一批任務裏面的打印會無序的打印出來,第二批任務會按照順序打印(帶有kkkk的),可是第一批跟第二批任務是穿插進行的有時候打印第一批裏面的,有時候打印第二批裏面的
而且已還回發現打印第一批任務的有好幾個線程(線程2,線程3...),,打印第二批任務的只有主線程
因此從這裏能夠看出,CPU執行任務的時候是給各個線程輪流使用的
可是你再看看下面的代碼
#pragma mark - 並行(並排跑,相似於賽跑) - (void)gcdDemo2 { // 並行隊列容易出錯!並行隊列不能控制新建線程的數量! dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcd2", DISPATCH_QUEUE_CONCURRENT); //第一輪任務 for (int i = 0; i < 10; ++i) { // 同步任務順序執行 dispatch_sync(q, ^{ NSLog(@"%@ %dkkkk", [NSThread currentThread], i); }); } // 第二輪任務 for (int i = 0; i < 10; ++i) { // 異步任務 dispatch_async(q, ^{ // [NSThread currentThread] 能夠在開發中,跟蹤當前線程 // num = 1,表示主線程 // num = 2,表示第2個子線程。。。 NSLog(@"%@ %d", [NSThread currentThread], i); }); } }
你會發現第一輪任務裏面的按照1,2,3,4,5,6,7.....這樣打印出來,而且第一輪任務執行完畢纔會執行第二輪任務
並且第二輪任務會無順序的打印出數字,這又爲何呢,就跟上一份代碼兩批任務的添加順序呢換了一下,結果差異怎麼那麼大呢?
由於第一輪任務使用的同步方法,什麼是同步方法呢?同步就是不會建立新的線程,當執行到那個同步任務的時候,當前的線程是誰,誰就去執行這些任務
而上面的代碼中,執行到同步任務的是主線程(num = 1),因此主線程就會按照順序去執行打印任務
而第二批任務是異步方法,異步方法會建立新的線程去執行任務,因此們的ThreadNum=2,3,4等等等,而且執行順序是沒法預估的(無序打印)
到這裏你可能還會有一個疑問就是爲何兩批任務不會像上一份代碼那樣,穿插着執行,而是先執行第一批在執行第二批呢?
這事由於第一批裏面用了同步而且執行到第一批的是主線程,下面咱們來詳細解釋一下
主線程是伴隨着程序運行而運行的,只要程序不掛掉,主線程就會一直運行,線程處理任務的時候是執行完一個,在執行第二個,一個線程不可能同時執行多個任務
,並且其餘線程都是由主線程去建立的,主線程就相似於一個超牛逼的人,而且他會造人技術,他須要別人幫忙的時候就會造一我的出來去幫他幹活,
可是這個超牛逼人每次只能幹一件事,幹完一件事才能幹另外一件,,,,你仔細看上面的代碼就會發現,第一批的10個任務是先添加到主線程裏面的,第二批的任務是後來出現的而且須要新的人去執行,,,,,,單此時主線程(超牛逼的那我的)已經有10個任務了,他必須先把這10個任務幹完才能去開闢一個新的線程(造人幫他幹活),因此
他會先把這10個任務完成之後,他纔會開闢新的線程去幫他執行另外的任務,,,,,,,,,從這裏就能夠很輕鬆的理解爲何先添加同步任務和先添加異步任務結果不一樣了
(先添加異步任務...上上份代碼... 就是先把造人的事情分給了主線程,然後纔給他分配的打印的任務),因此他造出來的人會和本身同時執行任務
由於每次建立隊列都很麻煩,因此蘋果給咱們提供了兩個能夠快速獲取的隊列---主隊列和全局隊列
下面是獲取代碼
// 每個應用程序都只有一個主線程 // 爲何須要在主線程上工做呢? // 在iOS開發中,全部UI的更新工做,都必須在主線程上執行! dispatch_queue_t q = dispatch_get_main_queue(); // 全局隊列與並行隊列的區別 // 1> 不須要建立,直接GET就能用 // 2> 兩個隊列的執行效果相同 // 3> 全局隊列沒有名稱,調試時,沒法確認準確隊列 // 記住:在開發中永遠用DISPATCH_QUEUE_PRIORITY_DEFAULT // 多線程的優先級反轉!低優先級的線程阻塞了高優先級的線程! dispatch_queue_t q =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
上面兩行代碼分別是獲取主隊列和全局隊列的方法
添加到主隊列裏的任務會放在主線程裏執行,這裏須要注意的是,若是你使用了主隊列,必定不要使用sync同步方法,而要是用異步方法
這個事爲何呢?1.主隊列是一個串行隊列,會依次執行任務,執行完一個執行另外一個
2.sync同步方法不會建立新的線程,會在執行到那句代碼所在的線程執行
由於主線程會一直執行到程序關閉,因此主線程裏面的任務是執行不完的,若是在主隊列裏添加同步任務,由於主線程裏的任務是執行不玩的,因此你添加的那個任務永遠不會被執行(這裏請注意,主隊列和主線程不是一回事,線程是處理任務的, 隊列是給線程送任務的)
在使用主隊列時應該使用sync異步方法去執行任務,這樣不用等主線程執行完畢就能夠執行到任務,須要注意的是在主隊列裏不會建立新的線程,即便使用async一步方法也不會建立新的線程
可能上面的主隊列比較難理解,下面來看個好理解的
#pragma mark 同步任務的阻塞 - (void)gcdSyncDemo { dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL); // 任務1 dispatch_sync(q, ^{ NSLog(@"sync %@", [NSThread currentThread]); // 任務2,同步裏面包含同步,會形成阻塞 dispatch_sync(q, ^{ // 永遠也不會執行到 NSLog(@"async %@", [NSThread currentThread]); }); }); }
上面是一個任務的嵌套,由於添加順序是任務1先添加,任務2後添加,而且是同步隊列,多以任務2會等任務1完成之後再執行,可是此時任務2在任務1的裏面,若是任務2沒有執行完,任務1是不可能執行完的,此時就是任務1等任務2完成 任務2,等任務1完成,兩個任務都等待對方完成本身才能完成,這樣兩個任務都不會完成
而主隊列裏面添加同步任務就相似上面的狀況,主隊列裏面一個巨大的任務等待小的同步任務完成,二小的同步任務等待包含他的巨打的任務完成,形成相互等待,結果就是誰完成不了