GCD死锁,及同步、异步、串行和并行队列组合情形

 
一、概述
1)队列用来存储代码任务,线程用来运行代码任务;
2)main()函数作为程序入口,整个程序默认运行在主线程中,程序代码任务默认存放在主队列中;
3)以下所谓阻塞线程是针对主线程而言(子线程阻塞在所不问,自己手动管理);队列阻塞主要是针对主队列(子队列阻塞在所不问,自己手动管理);
4)在线程中(如:主线程)添加block任务(以下简称“B”)到某个队列中,添加B本身也是一个任务即dispatch_sync或async代码本身也由当前线程(如:主线程)来运行(以下简称“A”)——简言之,代码就是任务,任务就是代码(所谓的block任务,实质就是block大括号里面的代码);
5)队列分三种:主队列、自定义串行队列(以下简称“自定串”)、并行队列;
6)线程阻塞原理(以主队列为例):系统会从主队列中按顺序取出某个任务放到主线程中运行,一旦该任务运行完毕,该任务即从主队列中结束销毁,系统就会自动从主队列中取出下一个任务又放到主线程中运行(相当于前一个),如此反复,直到主队列中的任务全部运行完毕;
 
二、异步并发
 
1)示例图
 
2)代码
dispatch_queue_t queue2 = dispatch_get_global_queue(0, 0);

dispatch_async(queue2, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"执行任务3-----%@", [NSThread currentThread]);
        }
    });

for (int i = 0; i < 10; i++) {
        NSLog(@"执行任务1-----%@", [NSThread currentThread]);
    }

//打印

2019-02-14 10:33:28.408678+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
2019-02-14 10:33:28.408685+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
2019-02-14 10:33:28.408935+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
2019-02-14 10:33:28.408935+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
2019-02-14 10:33:28.409076+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
2019-02-14 10:33:28.409098+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
2019-02-14 10:33:28.409185+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
2019-02-14 10:33:28.409232+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
2019-02-14 10:33:28.409301+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
2019-02-14 10:33:28.409618+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
2019-02-14 10:33:28.409873+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
2019-02-14 10:33:28.410141+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
2019-02-14 10:33:28.410480+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
2019-02-14 10:33:28.410794+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
2019-02-14 10:33:28.411167+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
2019-02-14 10:33:28.411486+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
2019-02-2019-02-14 10:33:28.411962+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
14 10:33:28.411763+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
2019-02-14 10:33:28.422231+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
2019-02-14 10:33:28.422250+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
3)分析
<1>首先添加GCD中的block任务(即“执行任务3”,相当于B)到并发队列queue2中,添加本身也是一个任务即A,该任务是存储在主队列中,由主线程运行;
<2>B被添加到queue2后,因为是异步,此时A不会停留在主队列中等待B执行完毕而是随即销毁,而后系统自动c主队列中取出下一个任务放到主线程中运行;
与此同时,系统又会单独开辟一个子线程来运行queue2中的B,所以即可由子线程来运行B;
<3>因此,此时系统有两条线程(主线程:number为1,name为main;子线程:number为3,name为null——因为没有取名字)在运行各自的任务,互不影响,交替执行;
 
三、几种情形
 
1)同步串行——主队列
结果:坏指令执行错误——死锁
 
//代码
dispatch_queue_t queue1 = dispatch_get_main_queue();

dispatch_sync(queue1, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"执行任务3-----%@", [NSThread currentThread]);
        }
    });

 

//错误

 
 
//分析
<1>A存储在主队列中,由主线来运行,B被添加到主队列中后,因为是同步,系统不会开辟一个子线程来运行B;
<2>A在主线程中运行完毕后,理应从主队列中销毁而执行下一个任务B,但因为是同步,A会依然停留在主队列中等待B运行完毕而不会立即销毁;又因为主队列是一个串行队列,因此B必须等到A执行完毕才能被系统取出放在主线程上运行(因为A排在B前面);
<3>局面:A在主队列中一直等待B的执行完毕,而B在主队列中一直等待A的执行完毕——“你等我,我等你”,死锁;
 
 
-------问题:死锁仅限于主队列吗?
 
//代码
dispatch_queue_t queue3 = dispatch_queue_create("myQueue3", DISPATCH_QUEUE_SERIAL);

NSLog(@"执行任务1----%@", [NSThread currentThread]);

    dispatch_async(queue3, ^{

        NSLog(@"执行任务2----%@", [NSThread currentThread]);

        dispatch_sync(queue3, ^{

            NSLog(@"执行任务3----%@", [NSThread currentThread]);

        });

        NSLog(@"执行任务4----%@", [NSThread currentThread]);

    });

    

    NSLog(@"执行任务5----%@", [NSThread currentThread]);

 

//打印

 

//分析
 <1>queue3自定义串行队列并且异步执行,所以系统会开辟一个子线程(number为3);主队列存储1、5和第一个async对应的A(以下简称“A1”),共三个任务;queue3存储2、3、4和第二个sync对应的A(以下简称“A2”),共四个任务;
<2>首先系统从主队列中取出1放到主线程上运行,待1运行完毕后(并在主队列中自动销毁),又取出A1放到主线程上运行,因为是异步,A1并不需要停留在主队列一直等待async中的block任务执行完毕,所以A1一执行完毕(并在主队列中自动销毁),系统又会从主队列中取出5放到主线程上运行,与此同时系统又会新开辟一个子线程来运行async中的block任务,该任务中的第一个小任务就是2——因此,此刻系统同时在跑两条线程,交替执行(谁先谁后由系统随机决定,没有定数);
<3>执行完1、5后,主队列中的非系统任务全部执行完毕,此时子线程运行完2后(并在queue3中自动销毁),系统又会从queue3中取出A2放到子线程中运行,A2运行完毕时,3被添加到了queue3中,同时因为是同步,所以A2依然会停留在queue3中一直等待3运行完毕(而不会即可自动销毁,只有等到3运行完毕时才会销毁),又因为queue3是串行队列,3排在A2后面一直在等待A2执行完毕——局面:A2与3相互等待,死锁;
<4>程序卡死在sync代码处,其后的代码(任务4)自然也就不能执行了;
 
所以,死锁不限于主队列,但限于串行队列!!!
 
 
------问题:如何解决死锁?
 
方案一:将A2和3放在不同的队列中
 
//代码
dispatch_queue_t queue3 = dispatch_queue_create("myQueue3", DISPATCH_QUEUE_SERIAL);

    dispatch_queue_t queue4 = dispatch_queue_create("myQueue4", DISPATCH_QUEUE_SERIAL);

NSLog(@"执行任务1----%@", [NSThread currentThread]);

    dispatch_async(queue3, ^{

        NSLog(@"执行任务2----%@", [NSThread currentThread]);

        dispatch_sync(queue4, ^{
            NSLog(@"执行任务3----%@", [NSThread currentThread]);
        });

        NSLog(@"执行任务4----%@", [NSThread currentThread]);
    });

    NSLog(@"执行任务5----%@", [NSThread currentThread]);

//打印

2019-02-15 12:28:51.782328+0800 MJ_iOS_Test[3879:128281] 执行任务1----<NSThread: 0x600003661480>{number = 1, name = main}
2019-02-15 12:28:51.782639+0800 MJ_iOS_Test[3879:128281] 执行任务5----<NSThread: 0x600003661480>{number = 1, name = main}
2019-02-15 12:28:51.782678+0800 MJ_iOS_Test[3879:128333] 执行任务2----<NSThread: 0x600003607fc0>{number = 3, name = (null)}
2019-02-15 12:28:51.782818+0800 MJ_iOS_Test[3879:128333] 执行任务3----<NSThread: 0x600003607fc0>{number = 3, name = (null)}
2019-02-15 12:28:51.782955+0800 MJ_iOS_Test[3879:128333] 执行任务4----<NSThread: 0x600003607fc0>{number = 3, name = (null)}

//分析

<1>dispatch_sync本身运行在子线程中,而该子线程对应的队列为queue3,因此A2(即添加任务本身)存放在queue3中,而3存放在queue4中;

<2>当子线程运行完毕2后(并随即自动销毁),此时系统是从queue3中取出4还是从queue4取出3放到子线程中运行呢?——因为同步,系统不会开辟新的线程,添加的block任务依然运行在当前线程中(number为3的子线程);同时,A2会一直停留在queue3中,直到3执行完毕才会自动销毁,又因为queue3是个串行队列而4排在A2后面,所以A2把4给堵住了,当3运行完毕后,A2销毁,系统就从queue3中取出4放到当前线程中运行;

注:此处将3放到一个并发队列中,效果是一样的;

 
方案二:异步添加3到queue3中
 
//代码
dispatch_queue_t queue3 = dispatch_queue_create("myQueue3", DISPATCH_QUEUE_SERIAL);

NSLog(@"执行任务1----%@", [NSThread currentThread]);

    dispatch_async(queue3, ^{

        NSLog(@"执行任务2----%@", [NSThread currentThread]);

        dispatch_async(queue3, ^{
            NSLog(@"执行任务3----%@", [NSThread currentThread]);
        });

        NSLog(@"执行任务4----%@", [NSThread currentThread]);
    });

    NSLog(@"执行任务5----%@", [NSThread currentThread]);

//打印

2019-02-15 14:09:46.953030+0800 MJ_iOS_Test[5523:191263] 执行任务1----<NSThread: 0x6000030aa900>{number = 1, name = main}
2019-02-15 14:09:46.953330+0800 MJ_iOS_Test[5523:191263] 执行任务5----<NSThread: 0x6000030aa900>{number = 1, name = main}
2019-02-15 14:09:46.953326+0800 MJ_iOS_Test[5523:191330] 执行任务2----<NSThread: 0x6000030c2880>{number = 3, name = (null)}
2019-02-15 14:09:46.953608+0800 MJ_iOS_Test[5523:191330] 执行任务4----<NSThread: 0x6000030c2880>{number = 3, name = (null)}
2019-02-15 14:09:46.954050+0800 MJ_iOS_Test[5523:191330] 执行任务3----<NSThread: 0x6000030c2880>{number = 3, name = (null)}

//分析——我门只分析3和4的顺序

<1>因为是异步且queue3非主队列,所以系统理应开辟一个新线程,但是运行完2后,此刻当前线程(number为3的子线程)处于闲置状态,为了节省资源,系统并不会真的开辟一个新线程,所有后面的任务依然会运行在当前子线程中(除非当前线程正在运行中,而同时要异步运行另一个任务,系统才会考虑开启一个新线程,或者手动强行开启一个新线程(异步并发));

<2>首先,我们明确下A2(第二个dispatch_async添加任务本身)、3和4在queue3中的存放顺序:

因为3的存放是由A2在线程上运行完成的,而在编译阶段A2并不会运行,但此时系统会给A2和4分配位置(依据代码顺序)——因此A2和4的存放是在编译阶段完成的,而3的存放是在运行阶段完成的,所以如下图所示

<3>因为异步,所以A2不会停留在queue3中一直等待3执行完毕而是将3添加到queue3中随即自动销毁,因为queue3是个串行队列,此时系统就从queue3中取出4放到当前子线程中运行,待4运行完毕,系统又会取出3放到当前子线程中运行;

说明:dispatch添加block任务(不论异步还是同步),都是在当前线程上运行完成的,因此该block任务的存放位置一定在dispatch后面所有外部任务(后面dispatch中的block任务以此类推)的位置后面———这点,请注意!!!

 
2)同步串行——自定义串行队列
结果:顺序执行
 
//代码
dispatch_queue_t queue3 = dispatch_queue_create("myQueue3", DISPATCH_QUEUE_SERIAL);

dispatch_sync(queue3, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"执行任务3-----%@", [NSThread currentThread]);
        }
    });

for (int i = 0; i < 10; i++) {
        NSLog(@"执行任务1-----%@", [NSThread currentThread]);
    }

//打印

2019-02-14 11:10:57.529267+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.529503+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.529627+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.529771+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.529903+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.530018+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.530147+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.530270+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.530418+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.530547+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.530666+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.530898+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.531152+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.549535+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.549711+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.549853+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.549989+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.550113+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.550247+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
2019-02-14 11:10:57.550381+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
//分析
<1>A存储在主队列中,由主线来运行,B被添加到自定义串行队列queue3中;因为是同步,系统不会开辟一个子线程来运行B;
<2>A在主线程运行完毕后会停留在主队列中一直等待B执行完毕,此时系统无法从主队列中取出下一个任务放到主线程上运行(因为被A堵住了),但会并且能从queue3中取出B放到主线程上运行;
<3>当主线程在运行“执行任务3”时,线程阻塞,当“执行任务3”运行完毕时,A收到消息则销毁,此时系统就会从主队列中取出下一个任务“执行任务1”放到主线程上运行;
 
说明:同样是同步串行,为什么此处就不会造成死锁——因为,A和B存放在不同队列中,不存在相互等待的局面;
 
3)同步并行
同“2)”;
 
//代码
dispatch_queue_t queue2 = dispatch_get_global_queue(0, 0);

for (int i = 0; i < 5; i++) {
        NSLog(@"执行任务1----%@", [NSThread currentThread]);
    }
    
    dispatch_async(queue2, ^{

        for (int i = 0; i < 5; i++) {
            NSLog(@"执行任务2----%@", [NSThread currentThread]);
        }

        dispatch_sync(queue2, ^{
            for (int i = 0; i < 5; i++) {
                NSLog(@"执行任务3----%@", [NSThread currentThread]);
            }
        });

        for (int i = 0; i < 5; i++) {
            NSLog(@"执行任务4----%@", [NSThread currentThread]);
        }
    });

    for (int i = 0; i < 5; i++) {
        NSLog(@"执行任务5----%@", [NSThread currentThread]);
    }

//打印

2019-02-15 17:19:50.417681+0800 MJ_iOS_Test[8640:311746] 执行任务1----<NSThread: 0x600002e96900>{number = 1, name = main}
2019-02-15 17:19:50.417926+0800 MJ_iOS_Test[8640:311746] 执行任务1----<NSThread: 0x600002e96900>{number = 1, name = main}
2019-02-15 17:19:50.418055+0800 MJ_iOS_Test[8640:311746] 执行任务1----<NSThread: 0x600002e96900>{number = 1, name = main}
2019-02-15 17:19:50.418175+0800 MJ_iOS_Test[8640:311746] 执行任务1----<NSThread: 0x600002e96900>{number = 1, name = main}
2019-02-15 17:19:50.418292+0800 MJ_iOS_Test[8640:311746] 执行任务1----<NSThread: 0x600002e96900>{number = 1, name = main}
2019-02-15 17:19:50.418449+0800 MJ_iOS_Test[8640:311746] 执行任务5----<NSThread: 0x600002e96900>{number = 1, name = main}
2019-02-15 17:19:50.418492+0800 MJ_iOS_Test[8640:311806] 执行任务2----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.418569+0800 MJ_iOS_Test[8640:311746] 执行任务5----<NSThread: 0x600002e96900>{number = 1, name = main}
2019-02-15 17:19:50.418727+0800 MJ_iOS_Test[8640:311806] 执行任务2----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.419157+0800 MJ_iOS_Test[8640:311746] 执行任务5----<NSThread: 0x600002e96900>{number = 1, name = main}
2019-02-15 17:19:50.419427+0800 MJ_iOS_Test[8640:311806] 执行任务2----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.419705+0800 MJ_iOS_Test[8640:311746] 执行任务5----<NSThread: 0x600002e96900>{number = 1, name = main}
2019-02-15 17:19:50.419987+0800 MJ_iOS_Test[8640:311806] 执行任务2----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.420301+0800 MJ_iOS_Test[8640:311746] 执行任务5----<NSThread: 0x600002e96900>{number = 1, name = main}
2019-02-15 17:19:50.427851+0800 MJ_iOS_Test[8640:311806] 执行任务2----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.428027+0800 MJ_iOS_Test[8640:311806] 执行任务3----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.428232+0800 MJ_iOS_Test[8640:311806] 执行任务3----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.429049+0800 MJ_iOS_Test[8640:311806] 执行任务3----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.429279+0800 MJ_iOS_Test[8640:311806] 执行任务3----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.429431+0800 MJ_iOS_Test[8640:311806] 执行任务3----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.429774+0800 MJ_iOS_Test[8640:311806] 执行任务4----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.430498+0800 MJ_iOS_Test[8640:311806] 执行任务4----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.430812+0800 MJ_iOS_Test[8640:311806] 执行任务4----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.431099+0800 MJ_iOS_Test[8640:311806] 执行任务4----<NSThread: 0x600002ef8680>{number = 3, name = (null)}
2019-02-15 17:19:50.431531+0800 MJ_iOS_Test[8640:311806] 执行任务4----<NSThread: 0x600002ef8680>{number = 3, name = (null)}

//分析

<1>当主线程(以下简称“T0”)运行完1后,程序走到第一个异步并发,此时系统必然开启一个新线程(以下简称“T1”),该线程运行第一个大block中的内容(以下简称“B1”),而主线程继续运行5,5和第一个大block中的内容的运行互不影响,交替执行,这点没问题;

<2>但是,问题来了—————第一个大block中的内容要先执行哪一个呢?为什么是2跟5交替执行,而其他都是顺序执行呢?

$0:首先要明确一点,不论是串行队列还是并行队列,其内部任务的添加都要遵循先来后到的顺序;

$1:各个队列中任务的位置顺序:主队列中存放三个任务,顺序依次为1、第一个async任务本身(以下简称“A1”)和5,均由主线程来运行并且A1不会等待,所以1和A1执行完毕才能执行5,这点没问题;queue2中存放2、第二个sync任务本身(以下简称“A2”)、3和4四个任务,按照上述分析,dispatch添加的block任务3会在2和4之后,所以存放顺序依次为2、A2、4和3,如下图;

 

$2:当程序进入B1后A2之前,此时的所有任务都只会运行在当前线程T1中,走到A2时,因为是同步,所以不会开启新线程,因此B1始终运行在T1上;而并发队列只有在异步时才有效,即如果只有一条线程时则只能顺序执行;

$3:因此,T1会先运行2,此时T0在运行5,两条线程互不影响,交替运行;待2运行完后,按顺序系统会从queue2中取出A2放到T1中运行,因为是同步,A2把3添加到queue2队列中后依然停留在queue2中等待3运行完毕而不会立即销毁;

----问题:此时queue2不会死锁吗?系统是从queue2中先取出3还是先取出4放到T1上运行呢?

第一个问题:因为只有一条线程,所以queue2虽为并行队列,但也只能按顺序运行其内部任务,但因为是并行队列,系统是可以从queue2中取出任何一个任务放到线程上运行,场景理解:

死锁:串行队列好比一根独木桥(横向距离刚好只能站住一个人,桥下是悬崖),桥上有ABCDE五个人依次排队进火车站检票入口(有且仅有一个);

同步并行:上述五个人站在大马路上(马路很宽)排队进检票口;

系统:检票员;

因此:如果是死锁,检票员无法跑到D身边让D先进检票口——否则会掉进悬崖;而同步并行就可以;

所以,串行队列,系统要按顺序取队列中的任务;并行,系统可以随机取————这点,请注意!!!;

 

第二个问题:因为A2一直在等待3运行完毕,即告诉系统要立马将3取出运行;

所以,同步即优先(立马)运行其添加的block任务————这点,请注意!!!

 
4)异步串行——主队列
结果:先执行主队列中后面的任务,完毕后再执行A和B;
 
//代码
dispatch_queue_t queue1 = dispatch_get_main_queue();

dispatch_async(queue1, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"执行任务3-----%@", [NSThread currentThread]);
        }
    });

for (int i = 0; i < 10; i++) {
        NSLog(@"执行任务1-----%@", [NSThread currentThread]);
    }

//打印

2019-02-14 15:18:24.484445+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.484665+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.484837+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.484978+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.485116+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.485296+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.485430+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.485566+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.485698+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.485815+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.507778+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.507968+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.508119+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.508252+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.508388+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.508541+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.508695+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.509382+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.509973+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
2019-02-14 15:18:24.510909+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
//分析
<1>异步会开启新线程,例外:如果是添加到主队列中,则不会开启子线程,依然由主线程来运行;
<2>如上分析,B的存放是在运行阶段完成,因此在主队列中存放顺序(先到后):A、“执行任务1”、B;
<2>因为是异步,所以A在主线程上运行完毕后会自动在主队列中销毁,此时系统会从主队列中取出下一个任务“执行任务1”放到主线程上运行,待“执行任务1”运行完毕后再来运行B;
 
5)异步串行——自定义串行队列
结果:同时交替执行;
 
//代码
dispatch_queue_t queue3 = dispatch_queue_create("myQueue3", DISPATCH_QUEUE_SERIAL);

dispatch_async(queue3, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"执行任务3-----%@", [NSThread currentThread]);
        }
    });

for (int i = 0; i < 10; i++) {
        NSLog(@"执行任务1-----%@", [NSThread currentThread]);
    }

//打印

2019-02-14 15:35:12.843681+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
2019-02-14 15:35:12.843686+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
2019-02-14 15:35:12.843933+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
2019-02-14 15:35:12.843999+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
2019-02-14 15:35:12.844065+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
2019-02-14 15:35:12.844208+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
2019-02-14 15:35:12.844348+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
2019-02-14 15:35:12.844474+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
2019-02-14 15:35:12.844482+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
2019-02-14 15:35:12.844614+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
2019-02-14 15:35:12.844743+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
2019-02-14 15:35:12.844769+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
2019-02-14 15:35:12.845040+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
2019-02-14 15:35:12.845234+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
2019-02-14 15:35:12.845559+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
2019-02-14 15:35:12.854636+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
2019-02-14 15:35:12.855004+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
2019-02-14 15:35:12.855578+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
2019-02-14 15:35:12.855858+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
2019-02-14 15:35:12.856068+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
//分析
<1>开启了子线程,主线程对应主队列,运行“执行任务1”;子线程对应queue3队列,运行执行任务3;
<2>两条线程运行各自的任务,互不影响,交替执行;
 
6)异步并行
如上述示例图分析,同“5)”;
补充:6)和5)两种情况,相对于主线程效果都一样——交替执行;但是其内部任务执行有区别:
 
<1>顺序添加两个任务到自定义串行队列中——情况“5)”
 
//代码
dispatch_queue_t queue3 = dispatch_queue_create("myQueue3", DISPATCH_QUEUE_SERIAL);

dispatch_async(queue3, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"执行任务3-----%@", [NSThread currentThread]);
        }
    });
    
    dispatch_async(queue3, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"执行任务3-2-----%@", [NSThread currentThread]);
        }
    });
    
    for (int i = 0; i < 10; i++) {
        NSLog(@"执行任务1-----%@", [NSThread currentThread]);
    }

//打印

2019-02-14 15:48:52.982315+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.982310+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
2019-02-14 15:48:52.982607+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.982607+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
2019-02-14 15:48:52.982759+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
2019-02-14 15:48:52.982759+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.982871+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
2019-02-14 15:48:52.982917+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.982970+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
2019-02-14 15:48:52.983061+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.983401+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
2019-02-14 15:48:52.983668+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.983945+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
2019-02-14 15:48:52.984186+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.984453+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
2019-02-14 15:48:52.984710+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.984928+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
2019-02-14 15:48:52.985130+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.994169+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
2019-02-14 15:48:52.994181+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.994355+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.994502+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.994671+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.994804+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.995173+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.995663+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.996280+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.996518+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.996819+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
2019-02-14 15:48:52.997497+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
//分析
<1>串行队列queue3中存储两个任务:“执行任务3”和“执行任务3-2”,主队列中存储三个任务:两个A和“执行任务1”;子线程运行queue3的任务,主线程运行主队列中的任务;
<2>“执行任务3”对应的A在主线程运行完毕后自动在主队列中销毁,系统就会从主队列中取出下一个任务即“执行任务3-2”对应的A;同时,“执行任务3”被添加到queue3中并在系统随即开辟的子线程中运行;
但同时,“执行任务3-2”也被添加到queue3中,并且其对应的A自动在主队列中销毁,此时,系统又会从主队列中取出下一个任务“执行任务1”;
<3>因此,此时有两条线程同时在运行:主线程运行“执行任务1”,子线程运行“执行任务3”;二者互不影响,交替执行;
<4>“执行任务3-2”需要等到“执行任务3”执行完毕后,才能被系统取出放到子线程中运行——因此,该任务最后运行;
 
<2>顺序添加两个任务到并行队列中——情况“6)”
 
//代码
dispatch_queue_t queue2 = dispatch_get_global_queue(0, 0);

dispatch_async(queue2, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"执行任务3-----%@", [NSThread currentThread]);
        }
    });
    
    dispatch_async(queue2, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"执行任务3-2-----%@", [NSThread currentThread]);
        }
    });
    
    for (int i = 0; i < 10; i++) {
        NSLog(@"执行任务1-----%@", [NSThread currentThread]);
    }

//打印

2019-02-14 16:06:55.818176+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
2019-02-14 16:06:55.818227+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
2019-02-14 16:06:55.818227+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
2019-02-14 16:06:55.818495+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
2019-02-14 16:06:55.818500+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
2019-02-14 16:06:55.818500+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
2019-02-14 16:06:55.818630+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
2019-02-14 16:06:55.818657+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
2019-02-14 16:06:55.818753+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
2019-02-14 16:06:55.818758+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
2019-02-14 16:06:55.819027+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
2019-02-14 16:06:55.819361+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
2019-02-14 16:06:55.819644+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
2019-02-14 16:06:55.820062+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
2019-02-14 16:06:55.820389+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
2019-02-14 16:06:55.820744+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
2019-02-14 16:06:55.821125+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
2019-02-14 16:06:55.821634+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = 2019-02-14 16:06:55.822389+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
(null)}
2019-02-14 16:06:55.821989+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
2019-02-14 16:06:55.833276+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
2019-02-14 16:06:55.833308+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
2019-02-14 16:06:55.833282+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
2019-02-14 16:06:55.833419+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
2019-02-14 16:06:55.833462+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
2019-02-14 16:06:55.833503+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
2019-02-14 16:06:55.833543+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
2019-02-14 16:06:55.833890+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
2019-02-14 16:06:55.834534+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
2019-02-14 16:06:55.835481+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
//分析
<1>此时有三条线程在跑:主线程运行“执行任务1”;number为3的子线程运行“执行任务3”;number为4的子线程运行“执行任务3-2”;
<2>各个线程间:运行各自的任务,互不影响,交替执行;
 
四、结论
 
1)异步、同步理解:——决定系统是否开启线程的能力(注:有能力开启,但并不必然要开启)
<1>block任务存放位置:不论异步还是同步,如果是同一串行队列,block任务的存放位置一定在dispatch后面所有外部任务的位置后面(后面dispatch中的block任务以此类推)——因为外部任务位置分配在编译阶段完成,而block任务添加是在运行阶段完成;
<2>是否开启新线程:同步一定不会开启新线程,任务只运行在当前线程中(主线程或子线程);异步:并发一定开启新线程,串行不一定,取决于是否主队列及是否有闲置子线程——如果是主队列,则依然运行在主线程中;如果系统已经开启了一个子线程且处于闲置状态,为节省资源,则依然会运行在该子线程中;
<3>A是否等待:同步,会等待阻塞队列;异步,不会等待(添加完B后随即自动销毁)不阻塞队列;
<4>同步添加的block任务必须优先执行(否则,A死不瞑目);异步该怎么执行就怎么执行(并行:一起执行;串行:顺序执行);
 
2)线程阻塞:线程正在运行某个任务,下一个任务只能等待该任务运行完毕才能运行(前提:都运行在同一个线程中)————同一时间,一个线程只能运行一个任务(一一对应);
 
3)串行、并行理解:——决定队列内部任务的执行方式
<1>串行:系统从队列中取出任务必须遵循先后顺序,从而决定任务的运行也是有先后顺序的——至于各个任务是否在同一条线程上运行、在哪条线程上运行,在所不问;
<2>并行:系统可以从队列中取出任意位置的任务,但任务的运行顺序取决于是否同时有多条线程——如果有多条线程,同一时间,系统同时取出多个任务并由多个线程同时运行;但是如果只有一个线程,通常为顺序执行(例外:同步添加的任务必须优先执行);
<3>不论串行还是并行队列,内部任务添加顺序都必须遵循先来后到的顺序(即内部任务的位置是有顺序的)——位置顺序分配见“1)<1>”;
 
4)死锁:
<1>本质:队列阻塞——同步串行,系统没有开辟新线程,B被添加在A所在队列中,A依然停留在所在队列中等待B执行完毕未自动销毁,从而堵住B,因为串行,B需要等待A执行完毕才能被执行,导致A和B相互等待;
<2>解决方案:要么将A和B放在两个不同队列中,要么异步添加(A运行完毕自动销毁,不等待不阻塞B);
<3>死锁不限于主队列,但仅限于串行队列(并行队列不存在死锁);死锁必然是同步串行,但同步串行并不必然是死锁——见“2)同步串行——自定义串行队列”;
<4>死锁是因为系统无法从串行队列中取出相应的任务放到当前线程中运行,而此时当前线程是闲置的,未阻塞;
 
5)A存储在添加B之前的当前线程(主线程或子线程)对应的队列中,B存储位置取决于添加队列类型,其是否由主线程来运行,取决于系统是否开启新线程;
6)不同线程间,运行任务互不影响,交替执行;不同队列可共用同一个线程,同一个队列中的不同任务可运行在不同线程上;
7)主线程:number为1,name为main;子线程:number大于1,name自定义;
 
 
 
说明:代码较为简单,主要是理论,就不上传GitHub了;
 
 
 
 
posted @ 2019-02-14 16:40  春天里的花骨朵  阅读(1513)  评论(0编辑  收藏  举报