经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » iOS » 查看文章
GCD死锁,及同步、异步、串行和并行队列组合情形
来源:cnblogs  作者:春天里的花骨朵  时间:2019/2/15 9:35:59  对本文有异议
 
一、概述
1)队列用来存储代码任务,线程用来运行代码任务;
2)main()函数作为程序入口,整个程序默认运行在主线程中,程序代码任务默认存放在主队列中;
3)以下所谓阻塞线程是针对主线程而言(子线程阻塞在所不问,自己手动管理);队列阻塞主要是针对主队列(子队列阻塞在所不问,自己手动管理);
4)在主线中添加block任务(以下简称“B”)到某个队列中,添加B本身也是一个任务即dispatch_sync代码本身由主线程来运行(以下简称“A”);
5)队列分三种:主队列、自定义串行队列(以下简称“自定串”)、并行队列;
6)线程阻塞原理(以主队列为例):系统会从主队列中按顺序取出某个任务放到主线程中运行,一旦该任务运行完毕,该任务即从主队列中结束销毁,系统就会自动从主队列中取出下一个任务又放到主线程中运行(相当于前一个),如此反复,直到主队列中的任务全部运行完毕;
 
二、异步并发
 
1)示例图
 
2)代码
  1. dispatch_queue_t queue2 = dispatch_get_global_queue(0, 0);
  2. dispatch_async(queue2, ^{
  3. for (int i = 0; i < 10; i++) {
  4. NSLog(@"执行任务3-----%@", [NSThread currentThread]);
  5. }
  6. });
  7. for (int i = 0; i < 10; i++) {
  8. NSLog(@"执行任务1-----%@", [NSThread currentThread]);
  9. }

//打印

  1. 2019-02-14 10:33:28.408678+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
  2. 2019-02-14 10:33:28.408685+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
  3. 2019-02-14 10:33:28.408935+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
  4. 2019-02-14 10:33:28.408935+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
  5. 2019-02-14 10:33:28.409076+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
  6. 2019-02-14 10:33:28.409098+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
  7. 2019-02-14 10:33:28.409185+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
  8. 2019-02-14 10:33:28.409232+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
  9. 2019-02-14 10:33:28.409301+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
  10. 2019-02-14 10:33:28.409618+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
  11. 2019-02-14 10:33:28.409873+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
  12. 2019-02-14 10:33:28.410141+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
  13. 2019-02-14 10:33:28.410480+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
  14. 2019-02-14 10:33:28.410794+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
  15. 2019-02-14 10:33:28.411167+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
  16. 2019-02-14 10:33:28.411486+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
  17. 2019-02-2019-02-14 10:33:28.411962+0800 MJ_iOS_Test[1864:38623] 执行任务3-----<NSThread: 0x600000c7b780>{number = 3, name = (null)}
  18. 14 10:33:28.411763+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
  19. 2019-02-14 10:33:28.422231+0800 MJ_iOS_Test[1864:38570] 执行任务1-----<NSThread: 0x600000c16980>{number = 1, name = main}
  20. 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)同步串行——主队列
结果:坏指令执行错误——死锁
 
//代码
  1. dispatch_queue_t queue1 = dispatch_get_main_queue();
  2. dispatch_sync(queue1, ^{
  3. for (int i = 0; i < 10; i++) {
  4. NSLog(@"执行任务3-----%@", [NSThread currentThread]);
  5. }
  6. });

 

//错误

 
 
//分析
<1>A存储在主队列中,由主线来运行,B被添加到主队列中后,因为是同步,系统不会开辟一个子线程来运行B;
<2>A在主线程中运行完毕后,理应从主队列中销毁而执行下一个任务B,但因为是同步,A会依然停留在主队列中等待B运行完毕;又因为主队列是一个串行队列,因此B必须等到A执行完毕才能被系统取出放在主线程上运行(因为A排在B前面);
<3>局面:A在主队列中一直等待B的执行完毕,而B在主队列中一直等待A的执行完毕——“你等我,我等你”,死锁;
 
2)同步串行——自定义串行队列
结果:顺序执行
 
//代码
  1. dispatch_queue_t queue3 = dispatch_queue_create("myQueue3", DISPATCH_QUEUE_SERIAL);
  2. dispatch_sync(queue3, ^{
  3. for (int i = 0; i < 10; i++) {
  4. NSLog(@"执行任务3-----%@", [NSThread currentThread]);
  5. }
  6. });
  7. for (int i = 0; i < 10; i++) {
  8. NSLog(@"执行任务1-----%@", [NSThread currentThread]);
  9. }

//打印

  1. 2019-02-14 11:10:57.529267+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  2. 2019-02-14 11:10:57.529503+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  3. 2019-02-14 11:10:57.529627+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  4. 2019-02-14 11:10:57.529771+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  5. 2019-02-14 11:10:57.529903+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  6. 2019-02-14 11:10:57.530018+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  7. 2019-02-14 11:10:57.530147+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  8. 2019-02-14 11:10:57.530270+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  9. 2019-02-14 11:10:57.530418+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  10. 2019-02-14 11:10:57.530547+0800 MJ_iOS_Test[2440:59133] 执行任务3-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  11. 2019-02-14 11:10:57.530666+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  12. 2019-02-14 11:10:57.530898+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  13. 2019-02-14 11:10:57.531152+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  14. 2019-02-14 11:10:57.549535+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  15. 2019-02-14 11:10:57.549711+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  16. 2019-02-14 11:10:57.549853+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  17. 2019-02-14 11:10:57.549989+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  18. 2019-02-14 11:10:57.550113+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  19. 2019-02-14 11:10:57.550247+0800 MJ_iOS_Test[2440:59133] 执行任务1-----<NSThread: 0x60000252ce40>{number = 1, name = main}
  20. 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;
 
//代码
  1. dispatch_queue_t queue1 = dispatch_get_main_queue();
  2. dispatch_async(queue1, ^{
  3. for (int i = 0; i < 10; i++) {
  4. NSLog(@"执行任务3-----%@", [NSThread currentThread]);
  5. }
  6. });
  7. for (int i = 0; i < 10; i++) {
  8. NSLog(@"执行任务1-----%@", [NSThread currentThread]);
  9. }

//打印

  1. 2019-02-14 15:18:24.484445+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
  2. 2019-02-14 15:18:24.484665+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
  3. 2019-02-14 15:18:24.484837+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
  4. 2019-02-14 15:18:24.484978+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
  5. 2019-02-14 15:18:24.485116+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
  6. 2019-02-14 15:18:24.485296+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
  7. 2019-02-14 15:18:24.485430+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
  8. 2019-02-14 15:18:24.485566+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
  9. 2019-02-14 15:18:24.485698+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
  10. 2019-02-14 15:18:24.485815+0800 MJ_iOS_Test[6008:173463] 执行任务1-----<NSThread: 0x600002642940>{number = 1, name = main}
  11. 2019-02-14 15:18:24.507778+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
  12. 2019-02-14 15:18:24.507968+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
  13. 2019-02-14 15:18:24.508119+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
  14. 2019-02-14 15:18:24.508252+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
  15. 2019-02-14 15:18:24.508388+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
  16. 2019-02-14 15:18:24.508541+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
  17. 2019-02-14 15:18:24.508695+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
  18. 2019-02-14 15:18:24.509382+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
  19. 2019-02-14 15:18:24.509973+0800 MJ_iOS_Test[6008:173463] 执行任务3-----<NSThread: 0x600002642940>{number = 1, name = main}
  20. 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)异步串行——自定义串行队列
结果:同时交替执行;
 
//代码
  1. dispatch_queue_t queue3 = dispatch_queue_create("myQueue3", DISPATCH_QUEUE_SERIAL);
  2. dispatch_async(queue3, ^{
  3. for (int i = 0; i < 10; i++) {
  4. NSLog(@"执行任务3-----%@", [NSThread currentThread]);
  5. }
  6. });
  7. for (int i = 0; i < 10; i++) {
  8. NSLog(@"执行任务1-----%@", [NSThread currentThread]);
  9. }

//打印

  1. 2019-02-14 15:35:12.843681+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
  2. 2019-02-14 15:35:12.843686+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
  3. 2019-02-14 15:35:12.843933+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
  4. 2019-02-14 15:35:12.843999+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
  5. 2019-02-14 15:35:12.844065+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
  6. 2019-02-14 15:35:12.844208+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
  7. 2019-02-14 15:35:12.844348+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
  8. 2019-02-14 15:35:12.844474+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
  9. 2019-02-14 15:35:12.844482+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
  10. 2019-02-14 15:35:12.844614+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
  11. 2019-02-14 15:35:12.844743+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
  12. 2019-02-14 15:35:12.844769+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
  13. 2019-02-14 15:35:12.845040+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
  14. 2019-02-14 15:35:12.845234+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
  15. 2019-02-14 15:35:12.845559+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
  16. 2019-02-14 15:35:12.854636+0800 MJ_iOS_Test[6248:181935] 执行任务3-----<NSThread: 0x6000011c9e00>{number = 3, name = (null)}
  17. 2019-02-14 15:35:12.855004+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
  18. 2019-02-14 15:35:12.855578+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
  19. 2019-02-14 15:35:12.855858+0800 MJ_iOS_Test[6248:181875] 执行任务1-----<NSThread: 0x6000011aae40>{number = 1, name = main}
  20. 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)”
 
//代码
  1. dispatch_queue_t queue3 = dispatch_queue_create("myQueue3", DISPATCH_QUEUE_SERIAL);
  2. dispatch_async(queue3, ^{
  3. for (int i = 0; i < 10; i++) {
  4. NSLog(@"执行任务3-----%@", [NSThread currentThread]);
  5. }
  6. });
  7. dispatch_async(queue3, ^{
  8. for (int i = 0; i < 10; i++) {
  9. NSLog(@"执行任务3-2-----%@", [NSThread currentThread]);
  10. }
  11. });
  12. for (int i = 0; i < 10; i++) {
  13. NSLog(@"执行任务1-----%@", [NSThread currentThread]);
  14. }

//打印

  1. 2019-02-14 15:48:52.982315+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  2. 2019-02-14 15:48:52.982310+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
  3. 2019-02-14 15:48:52.982607+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  4. 2019-02-14 15:48:52.982607+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
  5. 2019-02-14 15:48:52.982759+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
  6. 2019-02-14 15:48:52.982759+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  7. 2019-02-14 15:48:52.982871+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
  8. 2019-02-14 15:48:52.982917+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  9. 2019-02-14 15:48:52.982970+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
  10. 2019-02-14 15:48:52.983061+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  11. 2019-02-14 15:48:52.983401+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
  12. 2019-02-14 15:48:52.983668+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  13. 2019-02-14 15:48:52.983945+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
  14. 2019-02-14 15:48:52.984186+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  15. 2019-02-14 15:48:52.984453+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
  16. 2019-02-14 15:48:52.984710+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  17. 2019-02-14 15:48:52.984928+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
  18. 2019-02-14 15:48:52.985130+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  19. 2019-02-14 15:48:52.994169+0800 MJ_iOS_Test[6484:189759] 执行任务1-----<NSThread: 0x600000356840>{number = 1, name = main}
  20. 2019-02-14 15:48:52.994181+0800 MJ_iOS_Test[6484:189815] 执行任务3-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  21. 2019-02-14 15:48:52.994355+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  22. 2019-02-14 15:48:52.994502+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  23. 2019-02-14 15:48:52.994671+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  24. 2019-02-14 15:48:52.994804+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  25. 2019-02-14 15:48:52.995173+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  26. 2019-02-14 15:48:52.995663+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  27. 2019-02-14 15:48:52.996280+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  28. 2019-02-14 15:48:52.996518+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  29. 2019-02-14 15:48:52.996819+0800 MJ_iOS_Test[6484:189815] 执行任务3-2-----<NSThread: 0x600000320940>{number = 3, name = (null)}
  30. 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)”
 
//代码
  1. dispatch_queue_t queue2 = dispatch_get_global_queue(0, 0);
  2. dispatch_async(queue2, ^{
  3. for (int i = 0; i < 10; i++) {
  4. NSLog(@"执行任务3-----%@", [NSThread currentThread]);
  5. }
  6. });
  7. dispatch_async(queue2, ^{
  8. for (int i = 0; i < 10; i++) {
  9. NSLog(@"执行任务3-2-----%@", [NSThread currentThread]);
  10. }
  11. });
  12. for (int i = 0; i < 10; i++) {
  13. NSLog(@"执行任务1-----%@", [NSThread currentThread]);
  14. }

//打印

  1. 2019-02-14 16:06:55.818176+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
  2. 2019-02-14 16:06:55.818227+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
  3. 2019-02-14 16:06:55.818227+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
  4. 2019-02-14 16:06:55.818495+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
  5. 2019-02-14 16:06:55.818500+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
  6. 2019-02-14 16:06:55.818500+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
  7. 2019-02-14 16:06:55.818630+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
  8. 2019-02-14 16:06:55.818657+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
  9. 2019-02-14 16:06:55.818753+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
  10. 2019-02-14 16:06:55.818758+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
  11. 2019-02-14 16:06:55.819027+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
  12. 2019-02-14 16:06:55.819361+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
  13. 2019-02-14 16:06:55.819644+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
  14. 2019-02-14 16:06:55.820062+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
  15. 2019-02-14 16:06:55.820389+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
  16. 2019-02-14 16:06:55.820744+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
  17. 2019-02-14 16:06:55.821125+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
  18. 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}
  19. (null)}
  20. 2019-02-14 16:06:55.821989+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
  21. 2019-02-14 16:06:55.833276+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
  22. 2019-02-14 16:06:55.833308+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
  23. 2019-02-14 16:06:55.833282+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
  24. 2019-02-14 16:06:55.833419+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
  25. 2019-02-14 16:06:55.833462+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
  26. 2019-02-14 16:06:55.833503+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
  27. 2019-02-14 16:06:55.833543+0800 MJ_iOS_Test[6737:199038] 执行任务1-----<NSThread: 0x600002ed1180>{number = 1, name = main}
  28. 2019-02-14 16:06:55.833890+0800 MJ_iOS_Test[6737:199118] 执行任务3-----<NSThread: 0x600002eb2380>{number = 3, name = (null)}
  29. 2019-02-14 16:06:55.834534+0800 MJ_iOS_Test[6737:199117] 执行任务3-2-----<NSThread: 0x600002eb23c0>{number = 4, name = (null)}
  30. 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了;
 
 
 

原文链接:http://www.cnblogs.com/lybSkill/p/10375404.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号