iOS 開(kāi)發(fā)_GCD函數(shù)與隊(duì)列二、面試相關(guān)知識(shí)

【作者前言】:13年入圈眠砾,分享些本人工作中遇到的點(diǎn)點(diǎn)滴滴那些事兒虏劲,17年剛開(kāi)始寫(xiě)博客,高手勿噴褒颈!以分享交流為主柒巫,歡迎各路豪杰點(diǎn)評(píng)改進(jìn)!

1.應(yīng)用場(chǎng)景:

多線程神器---GCD哈肖,很多開(kāi)發(fā)的場(chǎng)景中吻育,我們都會(huì)使用到。

2.實(shí)現(xiàn)目標(biāo):

針對(duì)面試中可能遇到的問(wèn)題淤井,進(jìn)行反向的剖析知識(shí)點(diǎn)布疼。

3.代碼說(shuō)明:【比喻~隊(duì)列與函數(shù)存在一種關(guān)系:C4-2的組合關(guān)系】

1) 知識(shí)點(diǎn)預(yù)熱:首先需要了解同步&異步、串行&并行的關(guān)系
  • 同步執(zhí)行:
    dispatch_sync()币狠,這個(gè)函數(shù)會(huì)把一個(gè)block加入到指定的隊(duì)列中游两,而且會(huì)一直等到執(zhí)行完blcok,這個(gè)函數(shù)才返回漩绵。因此在block執(zhí)行完之前贱案,調(diào)用dispatch_sync方法的線程是阻塞的。 !>!>!即需要等待執(zhí)行結(jié)果后再執(zhí)行其他任務(wù)

  • 異步執(zhí)行
    dispatch_async()止吐,這個(gè)函數(shù)也會(huì)把一個(gè)block加入到指定的隊(duì)列中宝踪,但是和同步執(zhí)行不同的是,這個(gè)函數(shù)把block加入隊(duì)列后不等block的執(zhí)行就立刻返回了碍扔。 !>!>!即 無(wú)需等待執(zhí)行結(jié)果瘩燥,繼續(xù)執(zhí)行其他任務(wù)

小結(jié):
dispatch_async() 和 dispatch_sync() 他們的作用是將 任務(wù)(block)添加進(jìn)指定的隊(duì)列中。并根據(jù)是否為sync決定調(diào)用該函數(shù)的線程是否需要阻塞不同。
!!!:這里調(diào)用該函數(shù)的線程并不執(zhí)行 參數(shù)中指定的任務(wù)(block塊)厉膀,任務(wù)的執(zhí)行者是GCD分配給任務(wù)所在隊(duì)列的線程囤屹。
即 ---> 調(diào)用dispatch_sync() 和 dispatch_async() 的線程醋界,并不一定是任務(wù)(block塊)的真正執(zhí)行者

  • 串行隊(duì)列
    如dispatch_get_main_queue() 該隊(duì)列中所有任務(wù)都是串行依次執(zhí)行,可以保證在執(zhí)行某個(gè)任務(wù)時(shí)杈绸,在它前面進(jìn)入隊(duì)列的所有任務(wù)肯定執(zhí)行完了百新。對(duì)于每一個(gè)不同的串行隊(duì)列企软,系統(tǒng)會(huì)為這個(gè)隊(duì)列建立唯一的線程來(lái)執(zhí)行代碼

  • 并行隊(duì)列
    如dispatch_get_global_queue() 該隊(duì)列中的任務(wù)它們的執(zhí)行結(jié)束時(shí)間是不確定的,取決于每個(gè)任務(wù)的耗時(shí)饭望。并發(fā)隊(duì)列中的任務(wù):GCD會(huì)動(dòng)態(tài)分配多條線程來(lái)執(zhí)行澜倦。具體幾條線程取決于當(dāng)前內(nèi)存使用狀況聚蝶,線程池中線程數(shù)等因素

2) 代碼實(shí)操+詳細(xì)解讀分析
  • 【主隊(duì)列---串行同步】
/** 主隊(duì)列---串行同步 --測(cè)試
    不會(huì)開(kāi)啟線程  等待執(zhí)行
 */
- (void)mainSyncTest {
    NSLog(@"0");
    
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"1");
    });
    
    NSLog(@"2");
}

/****************控制臺(tái)輸出結(jié)果*******************/
 0 --- >崩潰Thread 1: EXC_BAD_INSTRUCTION 造成死鎖

/****************結(jié)果分析******************/
 打印 0 ---> 正常輸出后,
 當(dāng)前執(zhí)行這個(gè)dispatch_get_main_queue()隊(duì)列的是主線程藻治。
 執(zhí)行了dispatch_sync()函數(shù)后,將block(打印1) 添加到了main_queue中巷挥,
 同時(shí)調(diào)用dispatch_syn這個(gè)函數(shù)的線程(也就是主線程)會(huì)被阻塞桩卵,需要等待
 block(打印1)執(zhí)行完成,而此時(shí)執(zhí)行主線程隊(duì)列任務(wù)的線程正是主線程倍宾,
 此時(shí)他處于阻塞狀態(tài)雏节,所以block(打印1)永遠(yuǎn)不會(huì)被執(zhí)行,因此主線程一直處于阻塞狀態(tài)高职。

 因此這段代碼運(yùn)行后钩乍,并非卡在block(打印1)中無(wú)法返回,而是根本無(wú)法執(zhí)行到這個(gè)block(打印1)怔锌!
 導(dǎo)致你等我我等你寥粹,形成死鎖。無(wú)法打印 1 和 2
  • 【主隊(duì)列---串行異步】
/** 主隊(duì)列---串行異步 --測(cè)試
    不會(huì)開(kāi)啟線程埃元, 順序執(zhí)行
 */
- (void)mainAysncTest {
    NSLog(@"0");
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"1");
    });
    NSLog(@"2");
}
/****************控制臺(tái)輸出結(jié)果******************/
 0 2 1
/****************結(jié)果分析******************/
  dispatch_get_main_queue()屬于串行隊(duì)列涝涤,順序執(zhí)行
  dispatch_async()異步調(diào)用,不需要等待直接輸出執(zhí)行結(jié)果岛杀,
  即 0 ---> 2 ---> 1
  • 【全局隊(duì)列---并行同步】
/** 全局隊(duì)列---并行同步 --測(cè)試
     不會(huì)開(kāi)辟線程阔拳!
 */
- (void)globalSyncTest {
    for (int i = 0; i < 5; i ++) {
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"%d -- %@",i,[NSThread currentThread]);
        });
    }
    for (long i = 0; i < 100000; i ++) {
        //相當(dāng)于做個(gè)一定的延時(shí)處理...方便查看效果
    }
    NSLog(@"hello sync Global_Queue");
}

/****************控制臺(tái)輸出結(jié)果******************/
0 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
1 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
2 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
3 -- <NSThread: 0x6000003faa40>{number = 1, name = main}
4 -- <NSThread: 0x6000003faa40>{number = 1, name = main}

hello sync Global_Queue
/****************結(jié)果分析******************/
dispatch_get_global_queue() 屬于并行隊(duì)列,結(jié)果無(wú)序
dispatch_sync() 同步調(diào)用类嗤,需要等待執(zhí)行結(jié)束后在執(zhí)行其他任務(wù)糊肠,
即 阻塞當(dāng)前線程,順序執(zhí)行遗锣,故并行也無(wú)法發(fā)揮作用货裹,需要一個(gè)等一個(gè)依次執(zhí)行,
所以這里并沒(méi)有開(kāi)辟新的線程黄伊!
  • 【全局隊(duì)列---并行異步】
/** 全局隊(duì)列---并行異步 --測(cè)試
 */
- (void)globalAsyncTest {
    for (int i = 0; i < 5; i ++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"%d -- %@",i,[NSThread currentThread]);
        });
    }
    
    for (long i = 0; i < 100000; i ++) {
        //相當(dāng)于做個(gè)一定的延時(shí)處理...方便查看效果
    }
    NSLog(@"hello async Global_Queue");
}

/****************控制臺(tái)輸出結(jié)果******************/
 0 -- <NSThread: 0x6000032ae000>{number = 3, name = (null)}
 2 -- <NSThread: 0x6000032ae0c0>{number = 6, name = (null)}
 1 -- <NSThread: 0x6000032adfc0>{number = 4, name = (null)}
 3 -- <NSThread: 0x600003292940>{number = 5, name = (null)}
 4 -- <NSThread: 0x6000032ae000>{number = 3, name = (null)}

 hello async Global_Queue
/****************結(jié)果分析******************/
 dispatch_get_global_queue() 屬于并行隊(duì)列泪酱,執(zhí)行結(jié)果時(shí)序不一定
 dispatch_async()異步調(diào)用,不需要等待直接順序執(zhí)行还最,
 所以墓阀,線程并非只有一個(gè),開(kāi)辟了多個(gè)線程并行處理任務(wù)拓轻,輸出的結(jié)果的順序也不確定
  • 【通用的串行同步】
/** 串行同步隊(duì)列 --測(cè)試
    不開(kāi)辟線程   順序執(zhí)行
 */
- (void)serialSyncTest {
    dispatch_queue_t serialQueue = dispatch_queue_create("ypSerialQueue", DISPATCH_QUEUE_SERIAL);
    for (int i = 0; i < 5; i ++) {
        dispatch_sync(serialQueue, ^{
            NSLog(@"%d -- %@",i, [NSThread currentThread]);
        });
    }
    
    NSLog(@"hello sync serialQueue");
}
/****************控制臺(tái)輸出結(jié)果******************
 0 -- <NSThread: 0x600000365200>{number = 1, name = main}
 1 -- <NSThread: 0x600000365200>{number = 1, name = main}
 2 -- <NSThread: 0x600000365200>{number = 1, name = main}
 3 -- <NSThread: 0x600000365200>{number = 1, name = main}
 4 -- <NSThread: 0x600000365200>{number = 1, name = main}
 
 hello sync serialQueue
 */
/****************結(jié)果分析******************
 serialQueue 屬于串行隊(duì)列 不會(huì)開(kāi)辟線程 順序執(zhí)行
 dispatch_sync()同步調(diào)用斯撮,需要等待 順序執(zhí)行,
 
 串行隊(duì)列情況下扶叉,只能依次執(zhí)行勿锅,同步調(diào)用 等待出結(jié)果帕膜,故輸出如上
 */
  • 【通用的串行異步】
/** 串行異步隊(duì)列 --測(cè)試
    不開(kāi)辟線程   順序執(zhí)行
 */
- (void)serialAsyncTest {
    dispatch_queue_t serialQueue = dispatch_queue_create("ypSerialQueue", DISPATCH_QUEUE_SERIAL);
    for (int i = 0; i < 5; i ++) {
        dispatch_async(serialQueue, ^{
            NSLog(@"%d -- %@",i, [NSThread currentThread]);
        });
    }
    
     NSLog(@"hello serial Queue");
}
/****************控制臺(tái)輸出結(jié)果******************
 hello serial Queue
 
 0 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
 1 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
 2 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
 3 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
 4 -- <NSThread: 0x600003904d40>{number = 3, name = (null)}
 */
/****************結(jié)果分析******************
 serialQueue 屬于串行隊(duì)列 不會(huì)開(kāi)辟線程 順序執(zhí)行
 dispatch_async()異步調(diào)用,不需要等待直接順序執(zhí)行溢十,
 
 串行隊(duì)列情況下垮刹,只能依次執(zhí)行,異步調(diào)用直接出結(jié)果张弛,故輸出如上
 */
  • 【通用的并行同步】
/** 并行同步 ---測(cè)試
    不會(huì)創(chuàng)建線程  順序執(zhí)行
*/
- (void)concurrentSyncTest {
    //創(chuàng)建并發(fā)隊(duì)列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("ypConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 5; i ++) {
        dispatch_sync(concurrentQueue, ^{
            NSLog(@"%d -- %@",i, [NSThread currentThread]);
        });
    }
    
    NSLog(@"hello sync concurrent Queue");
    
}
/****************控制臺(tái)輸出結(jié)果******************
 0 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
 1 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
 2 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
 3 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
 4 -- <NSThread: 0x6000020ee940>{number = 1, name = main}
 
 hello sync concurrent Queue
 */

/****************結(jié)果分析******************
 concurrentQueue 屬于并行隊(duì)列荒典,執(zhí)行結(jié)果時(shí)序不一定
 dispatch_sync()同步調(diào)用,需要等待 順序執(zhí)行吞鸭,
 只要同步 就等待執(zhí)行寺董, 所以沒(méi)有開(kāi)辟線程  結(jié)果如上
 */
  • 【通用的并行異步】
/** 并行異步:*/
- (void)concurrentAsyncTest {
    //創(chuàng)建并發(fā)隊(duì)列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("ypconcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 5; i ++) {
        dispatch_async(concurrentQueue, ^{
            NSLog(@"%d -- %@",i, [NSThread currentThread]);
        });
    }
    
    for (long i = 0; i < 100000; i ++) {
        //相當(dāng)于做個(gè)一定的延時(shí)處理...方便查看效果
    }
    NSLog(@"hello concurrent Queue");
    
}
/****************控制臺(tái)輸出結(jié)果******************/
 0 -- <NSThread: 0x600001633600>{number = 3, name = (null)}
 3 -- <NSThread: 0x600001633580>{number = 5, name = (null)}
 2 -- <NSThread: 0x60000160d380>{number = 4, name = (null)}
 1 -- <NSThread: 0x600001633500>{number = 6, name = (null)}
 4 -- <NSThread: 0x600001633580>{number = 5, name = (null)}
 
 hello concurrent Queue
/****************結(jié)果分析******************/
 concurrentQueue 屬于并行隊(duì)列,執(zhí)行結(jié)果時(shí)序不一定
 dispatch_async() 異步調(diào)用刻剥,不需要等待直接順序執(zhí)行遮咖,
 所以,線程并非只有一個(gè)造虏,開(kāi)辟了多個(gè)線程并行處理任務(wù)御吞,輸出的結(jié)果的順序也不確定
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市酗电,隨后出現(xiàn)的幾起案子魄藕,更是在濱河造成了極大的恐慌,老刑警劉巖撵术,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件背率,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡嫩与,警方通過(guò)查閱死者的電腦和手機(jī)寝姿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)划滋,“玉大人饵筑,你說(shuō)我怎么就攤上這事〈ζ海” “怎么了根资?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)同窘。 經(jīng)常有香客問(wèn)我玄帕,道長(zhǎng),這世上最難降的妖魔是什么想邦? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任裤纹,我火速辦了婚禮,結(jié)果婚禮上丧没,老公的妹妹穿的比我還像新娘鹰椒。我一直安慰自己锡移,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布漆际。 她就那樣靜靜地躺著淆珊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪奸汇。 梳的紋絲不亂的頭發(fā)上套蒂,一...
    開(kāi)封第一講書(shū)人閱讀 51,775評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音茫蛹,去河邊找鬼。 笑死烁挟,一個(gè)胖子當(dāng)著我的面吹牛婴洼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播撼嗓,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼柬采,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了且警?” 一聲冷哼從身側(cè)響起粉捻,我...
    開(kāi)封第一講書(shū)人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎斑芜,沒(méi)想到半個(gè)月后肩刃,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杏头,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年盈包,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片醇王。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呢燥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出寓娩,到底是詐尸還是另有隱情叛氨,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布棘伴,位于F島的核電站寞埠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏排嫌。R本人自食惡果不足惜畸裳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淳地。 院中可真熱鬧怖糊,春花似錦帅容、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至扰魂,卻和暖如春麦乞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背劝评。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工姐直, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蒋畜。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓声畏,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親姻成。 傳聞我的和親對(duì)象是個(gè)殘疾皇子插龄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容