美文网首页
多线程(二)队列相关的常见面试题

多线程(二)队列相关的常见面试题

作者: PerryMorning | 来源:发表于2020-01-20 17:49 被阅读0次

    在上一篇文章中,我们主要分析了同步、异步,并发队列和串行队列。相信看过的朋友应该有初步的认识,但是总觉得朦朦胧胧,今天我们通过几个例子,来进一步认识队列在开发过程中怎么使用。

    注:本文所举的几个例子,都是在主线程中运行。

    demo1

    下面代码是否可以正常运行,如果可用正常运行,会输出什么结果:

        NSLog(@"执行任务1");
        
        dispatch_queue_t queue = dispatch_get_main_queue();
        dispatch_sync(queue, ^{
            NSLog(@"执行任务2");
        });
        
        NSLog(@"执行任务3");
    

    运行以上代码,报错,错误原因:死锁。
    下面我们来分析一下是什么原因导致的。
    1.这段代码里有三个任务,分别是任务1,任务2,任务3。任务1和任务3运行在主线程,任务2运行在主队列;
    2.主线程也是在主队列中的一个任务,可以认为先从主队列中取出,开始执行任务1;
    3.代码运行到开始执行任务2,由于是sync,会阻塞当前任务,即任务3被阻断,等待任务2完成后,继续执行;
    4.任务2在主队列中,按照队列的规则,FIFO,需要等待之前的任务(A)执行完成后,任务2方可出队执行;
    5.任务A执行完成,其实就是等待任务3执行完成;
    注意:此时死锁已经产生,任务2阻断了任务3的继续执行,想要执行任务2,需要等待主队列之前的任务完成出队,之前的任务又在等待任务3执行。循环等待,故而产生死锁。

    答案:这段代码不能正常运行,会产生死锁,原因见以上5条。

    demo2

    问题:以下代码是在主线程执行的,会不会产生死锁?

    // 问题:以下代码是在主线程执行的,会不会产生死锁?不会!
        NSLog(@"执行任务1");
        
        dispatch_queue_t queue = dispatch_get_main_queue();
        dispatch_async(queue, ^{
            NSLog(@"执行任务2");
        });
        
        NSLog(@"执行任务3");
        
        // dispatch_async不要求立马在当前线程同步执行任务
    

    运行代码,可以正常运行,结果如下:

    2020-01-20 17:10:38.830762+0800 Interview04-gcd[8327:1668596] 执行任务1
    2020-01-20 17:10:38.830950+0800 Interview04-gcd[8327:1668596] 执行任务3
    2020-01-20 17:10:38.852216+0800 Interview04-gcd[8327:1668596] 执行任务2
    

    分析:
    对比第一道题目,这里不同的地方是任务2是在异步主队列中执行。
    也就是说任务2不会阻塞任务3 的执行,任务3执行完成后,从主队列中取出任务2,执行。
    所以我们看到的执行顺序是任务1,任务3,任务2。
    和执行结果一致。

    答案:不会产生死锁

    demo3

    问题:以下代码是在主线程执行的,会不会产生死锁?

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

    运行结果:崩溃,依旧产生死锁。
    分析:其实这个和第一道题目是同样的道理,任务2、3、4在同一个队列里。任务3阻塞了任务4,同时在等待任务4的完成,造成死锁。
    第一道题目是在主队列中,其实主队列也是一个串行队列。

    答案:会产生死锁。

    demo4

    问题:以下代码是在主线程执行的,会不会产生死锁?

        NSLog(@"执行任务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(@"执行任务2");
            
            dispatch_sync(queue2, ^{ // 1
                NSLog(@"执行任务3");
            });
            
            NSLog(@"执行任务4");
        });
        
        NSLog(@"执行任务5");
    

    运行不会产生死锁,结果如下:

    2020-01-20 17:39:39.733786+0800 Interview04-gcd[8844:1771353] 执行任务1
    2020-01-20 17:39:39.733951+0800 Interview04-gcd[8844:1771353] 执行任务5
    2020-01-20 17:39:39.733969+0800 Interview04-gcd[8844:1771764] 执行任务2
    2020-01-20 17:39:39.734084+0800 Interview04-gcd[8844:1771764] 执行任务3
    2020-01-20 17:39:39.734193+0800 Interview04-gcd[8844:1771764] 执行任务4
    

    分析:与题目3相比,虽然任务3阻塞了任务4,但是任务3和任务4是在不同的队列中,任务4会等待任务3执行完成后,继续执行。最终的执行顺序就是 任务1,任务5,任务2,任务3,任务4.

    答案:不会产生死锁。

    demo5

    问题:以下代码是在主线程执行的,会不会产生死锁?

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

    运行不会产生死锁,结果如下:

    2020-01-20 17:43:45.141209+0800 Interview04-gcd[8966:1786471] 执行任务1
    2020-01-20 17:43:45.141392+0800 Interview04-gcd[8966:1786471] 执行任务5
    2020-01-20 17:43:45.141403+0800 Interview04-gcd[8966:1786985] 执行任务2
    2020-01-20 17:43:45.141545+0800 Interview04-gcd[8966:1786985] 执行任务3
    2020-01-20 17:43:45.141648+0800 Interview04-gcd[8966:1786985] 执行任务4
    

    分析:任务2、3、4都在同一个并行队列中,任务3虽然阻塞了任务4,但是由于是在并行队列中,并不影响任务3的执行,任务3 执行完成后,继续执行任务4。最终的执行顺序就是 任务1,任务5,任务2,任务3,任务4。

    答案:不会产生死锁。

    总结

    1.在同步(dispatch_sync())中,往当前串行队列添加任务就会产生死锁;
    2.其他情况不会产生死锁。

    相关文章

      网友评论

          本文标题:多线程(二)队列相关的常见面试题

          本文链接:https://www.haomeiwen.com/subject/pmvjzctx.html