多線程(二)隊列相關的常見面試題

在上一篇文章中,我們主要分析了同步、異步,并發(fā)隊列和串行隊列。相信看過的朋友應該有初步的認識,但是總覺得朦朦朧朧,今天我們通過幾個例子,來進一步認識隊列在開發(fā)過程中怎么使用。

注:本文所舉的幾個例子,都是在主線程中運行。

demo1

下面代碼是否可以正常運行,如果可用正常運行,會輸出什么結果:

    NSLog(@"執(zhí)行任務1");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"執(zhí)行任務2");
    });
    
    NSLog(@"執(zhí)行任務3");

運行以上代碼,報錯,錯誤原因:死鎖。
下面我們來分析一下是什么原因導致的。
1.這段代碼里有三個任務,分別是任務1,任務2,任務3。任務1和任務3運行在主線程,任務2運行在主隊列;
2.主線程也是在主隊列中的一個任務,可以認為先從主隊列中取出,開始執(zhí)行任務1;
3.代碼運行到開始執(zhí)行任務2,由于是sync,會阻塞當前任務,即任務3被阻斷,等待任務2完成后,繼續(xù)執(zhí)行;
4.任務2在主隊列中,按照隊列的規(guī)則,F(xiàn)IFO,需要等待之前的任務(A)執(zhí)行完成后,任務2方可出隊執(zhí)行;
5.任務A執(zhí)行完成,其實就是等待任務3執(zhí)行完成;
注意:此時死鎖已經(jīng)產(chǎn)生,任務2阻斷了任務3的繼續(xù)執(zhí)行,想要執(zhí)行任務2,需要等待主隊列之前的任務完成出隊,之前的任務又在等待任務3執(zhí)行。循環(huán)等待,故而產(chǎn)生死鎖。

答案:這段代碼不能正常運行,會產(chǎn)生死鎖,原因見以上5條。

demo2

問題:以下代碼是在主線程執(zhí)行的,會不會產(chǎn)生死鎖?

// 問題:以下代碼是在主線程執(zhí)行的,會不會產(chǎn)生死鎖?不會!
    NSLog(@"執(zhí)行任務1");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        NSLog(@"執(zhí)行任務2");
    });
    
    NSLog(@"執(zhí)行任務3");
    
    // dispatch_async不要求立馬在當前線程同步執(zhí)行任務

運行代碼,可以正常運行,結果如下:

2020-01-20 17:10:38.830762+0800 Interview04-gcd[8327:1668596] 執(zhí)行任務1
2020-01-20 17:10:38.830950+0800 Interview04-gcd[8327:1668596] 執(zhí)行任務3
2020-01-20 17:10:38.852216+0800 Interview04-gcd[8327:1668596] 執(zhí)行任務2

分析:
對比第一道題目,這里不同的地方是任務2是在異步主隊列中執(zhí)行。
也就是說任務2不會阻塞任務3 的執(zhí)行,任務3執(zhí)行完成后,從主隊列中取出任務2,執(zhí)行。
所以我們看到的執(zhí)行順序是任務1,任務3,任務2。
和執(zhí)行結果一致。

答案:不會產(chǎn)生死鎖

demo3

問題:以下代碼是在主線程執(zhí)行的,會不會產(chǎn)生死鎖?

    NSLog(@"執(zhí)行任務1");
    
    dispatch_queue_t queue = dispatch_queue_create("myqueu", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{ // 0
        NSLog(@"執(zhí)行任務2");
        
        dispatch_sync(queue, ^{ // 1
            NSLog(@"執(zhí)行任務3");
        });
    
        NSLog(@"執(zhí)行任務4");
    });
    
    NSLog(@"執(zhí)行任務5");

運行結果:崩潰,依舊產(chǎn)生死鎖。
分析:其實這個和第一道題目是同樣的道理,任務2、3、4在同一個隊列里。任務3阻塞了任務4,同時在等待任務4的完成,造成死鎖。
第一道題目是在主隊列中,其實主隊列也是一個串行隊列。

答案:會產(chǎn)生死鎖。

demo4

問題:以下代碼是在主線程執(zhí)行的,會不會產(chǎn)生死鎖?

    NSLog(@"執(zhí)行任務1");
    
    dispatch_queue_t queue = dispatch_queue_create("myqueu", DISPATCH_QUEUE_SERIAL);
//    dispatch_queue_t queue2 = dispatch_queue_create("myqueu2", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue2 = dispatch_queue_create("myqueu2", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{ // 0
        NSLog(@"執(zhí)行任務2");
        
        dispatch_sync(queue2, ^{ // 1
            NSLog(@"執(zhí)行任務3");
        });
        
        NSLog(@"執(zhí)行任務4");
    });
    
    NSLog(@"執(zhí)行任務5");

運行不會產(chǎn)生死鎖,結果如下:

2020-01-20 17:39:39.733786+0800 Interview04-gcd[8844:1771353] 執(zhí)行任務1
2020-01-20 17:39:39.733951+0800 Interview04-gcd[8844:1771353] 執(zhí)行任務5
2020-01-20 17:39:39.733969+0800 Interview04-gcd[8844:1771764] 執(zhí)行任務2
2020-01-20 17:39:39.734084+0800 Interview04-gcd[8844:1771764] 執(zhí)行任務3
2020-01-20 17:39:39.734193+0800 Interview04-gcd[8844:1771764] 執(zhí)行任務4

分析:與題目3相比,雖然任務3阻塞了任務4,但是任務3和任務4是在不同的隊列中,任務4會等待任務3執(zhí)行完成后,繼續(xù)執(zhí)行。最終的執(zhí)行順序就是 任務1,任務5,任務2,任務3,任務4.

答案:不會產(chǎn)生死鎖。

demo5

問題:以下代碼是在主線程執(zhí)行的,會不會產(chǎn)生死鎖?

    NSLog(@"執(zhí)行任務1");
    
    dispatch_queue_t queue = dispatch_queue_create("myqueu", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{ // 0
        NSLog(@"執(zhí)行任務2");
        
        dispatch_sync(queue, ^{ // 1
            NSLog(@"執(zhí)行任務3");
        });
        
        NSLog(@"執(zhí)行任務4");
    });
    
    NSLog(@"執(zhí)行任務5");

運行不會產(chǎn)生死鎖,結果如下:

2020-01-20 17:43:45.141209+0800 Interview04-gcd[8966:1786471] 執(zhí)行任務1
2020-01-20 17:43:45.141392+0800 Interview04-gcd[8966:1786471] 執(zhí)行任務5
2020-01-20 17:43:45.141403+0800 Interview04-gcd[8966:1786985] 執(zhí)行任務2
2020-01-20 17:43:45.141545+0800 Interview04-gcd[8966:1786985] 執(zhí)行任務3
2020-01-20 17:43:45.141648+0800 Interview04-gcd[8966:1786985] 執(zhí)行任務4

分析:任務2、3、4都在同一個并行隊列中,任務3雖然阻塞了任務4,但是由于是在并行隊列中,并不影響任務3的執(zhí)行,任務3 執(zhí)行完成后,繼續(xù)執(zhí)行任務4。最終的執(zhí)行順序就是 任務1,任務5,任務2,任務3,任務4。

答案:不會產(chǎn)生死鎖。

總結

1.在同步(dispatch_sync())中,往當前串行隊列添加任務就會產(chǎn)生死鎖;
2.其他情況不會產(chǎn)生死鎖。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容