欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2022-04-09 18:33:39
一、概述 1)队列用来存储代码任务,线程用来运行代码任务; 2)main()函数作为程序入口,整个程序默认运行在主线程中,程序代码任务默认存放在主队列中; 3)以下所谓阻塞线程是针对主线程而言(子线程阻塞在所不问,自己手动管理);队列阻塞主要是针对主队列(子队列阻塞在所不问,自己手动管理); 4)在 ......
 
一、概述
1)队列用来存储代码任务,线程用来运行代码任务;
2)main()函数作为程序入口,整个程序默认运行在主线程中,程序代码任务默认存放在主队列中;
3)以下所谓阻塞线程是针对主线程而言(子线程阻塞在所不问,自己手动管理);队列阻塞主要是针对主队列(子队列阻塞在所不问,自己手动管理);
4)在主线中添加block任务(以下简称“b”)到某个队列中,添加b本身也是一个任务即dispatch_sync代码本身由主线程来运行(以下简称“a”);
5)队列分三种:主队列、自定义串行队列(以下简称“自定串”)、并行队列;
6)线程阻塞原理(以主队列为例):系统会从主队列中按顺序取出某个任务放到主线程中运行,一旦该任务运行完毕,该任务即从主队列中结束销毁,系统就会自动从主队列中取出下一个任务又放到主线程中运行(相当于前一个),如此反复,直到主队列中的任务全部运行完毕;
 
二、异步并发
 
1)示例图
GCD死锁,及同步、异步、串行和并行队列组合情形
 
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执行完毕,而是由系统自动返回到主队列中取出下一个任务放到主线程中运行;
与此同时,系统又会单独开辟一个子线程来运行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]);
        }
    });

 

//错误

GCD死锁,及同步、异步、串行和并行队列组合情形
 
 
//分析
<1>a存储在主队列中,由主线来运行,b被添加到主队列中后,因为是同步,系统不会开辟一个子线程来运行b;
<2>a在主线程中运行完毕后,理应从主队列中销毁而执行下一个任务b,但因为是同步,a会依然停留在主队列中等待b运行完毕;又因为主队列是一个串行队列,因此b必须等到a执行完毕才能被系统取出放在主线程上运行(因为a排在b前面);
<3>局面:a在主队列中一直等待b的执行完毕,而b在主队列中一直等待a的执行完毕——“你等我,我等你”,死锁;
 
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”放到主线程上运行;
 
3)同步并行
同“2)”;
补充:如果在该并行队列中有其他任务时异步执行的,则系统开启新线程,与主线程互不影响,交替执行;
 
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>因为是异步,所以a在主线程上运行完毕后会自动在主队列中销毁,此时系统会从主队列中取出下一个任务“执行任务1”放到主线程上运行,待“执行任务1”运行完毕后再来运行b——此时,三个任务都存储在主队列中,同时“执行任务1”存储在a和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)a自始存储在主队列中并由主线程来运行;b初始并不必然存储在主队列中,取决于目标队列类型,是否由主线程来运行,取决于系统是否开启新线程;
2)同步:只运行在主线程中,a会在主队列中一直等待b执行完毕;异步:开启新线程,a不会等待;
3)线程阻塞:线程正在运行某个任务,下一个任务只能等待该任务运行完毕才能运行(前提:都运行在同一个线程中);
4)添加b到主队列:同步,死锁;异步:运行在主线程中,不会开启新线程;
5)死锁本质:队列阻塞———添加任务a和被添加任务b都存储在主队列中,因为同步,系统不会开辟新线程,而a运行完毕后也不会从主队列中销毁,造成a等待b,b等待a;
<1>因此,任何一个队列,只要其中前后两个任务相互等待就会造成死锁;而此时对应的线程是闲置的,并没有阻塞;
<2>解决方案:要么两个任务放在不同队列中,要么添加任务(a)执行完毕后使其在队列中销毁(即异步);
6)不同线程间,运行任务互不影响,交替执行;不同队列可共用同一个线程,同一个队列中的不同任务可运行在不同线程上;
7)主线程:number为1,name为main;子线程:number大于1,name自定义;
8)异步:队列性质决定线程性质(主线程还是子线程)及运行顺序——见“6)异步并行”;
 
 
说明:代码较为简单,主要是理论,就不上传github了;