美文网首页多线程iOSiOS点点滴滴
4.4 GCD->1.0 GCD简介和使用

4.4 GCD->1.0 GCD简介和使用

作者: 蓝田_Loto | 来源:发表于2016-04-18 14:15 被阅读181次

    本文并非最终版本,如果想要关注更新或更正的内容请关注文集,联系方式详见文末,如有疏忽和遗漏,欢迎指正。


    本文相关目录:
    ==================== 所属文集:4.0 多线程 ====================
    4.1 多线程基础->1.0 进程 & 线程
    ······················ 2.0 多线程简介
    4.2 pthread
    4.3 NSThread->1.0 创建线程
    ····················· 2.0 线程属性
    ····················· 3.0 线程状态/线程生命周期
    ····················· 4.0 多线程安全隐患
    ····················· 5.0 线程间通讯和常用方法
    4.4 GCD->1.0 GCD简介和使用
    ·············· 2.0 线程间的通信
    ·············· 3.0 其他用法
    ·············· 4.0 GCD 的定时器事件
    4.5 NSOperation->1.0 NSOperation简介
    ························ 2.0 NSOperationQueue
    ························ 3.0 线程间通信
    ························ 4.0 自定义NSOperation
    4.6 RunLoop - 运行循环
    ===================== 所属文集:4.0 多线程 =====================


    1.1 GCD简介

    GCD概念 :Grand Central Dispatch
    • 纯C语言,提供了非常多强大的函数
    GCD 的优势:
    • GCD是苹果公司为多核的并行运算提出的解决方案
    • GCD会自动利用更多的CPU内核(比如双核、四核)
    • GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
    • 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
    GCD的两个核心概念:
    (1) 任务:执行什么操作
    
    (2) 队列:用来存放任务
    
    注意:
    (1)GCD存在于 libdispatch 这个库中,这个调度库包含了GCD的所有的东西,但任何IOS程序,默认就加载了这个库,在程序运行的过程中会动态的加载这个库,不需要我们手动导入。
    
    Paste_Image.png
    (2)GCD是纯C语言的,因此我们在编写GCD相关代码的时候,面对的函数,而不是方法。
    
    (3)GCD中的函数大多数都以dispatch开头。
    

    1.2 GCD的使用

    GCD的使用步骤:

    步骤1 : 创建队列

    步骤2 : 创建任务

    - 确定想做的事情
    

    步骤3:把任务添加到队列

    - GCD会自动将队列中的任务取出,放到对应的线程中执行
    
    - 任务的取出遵循队列的FIFO原则:先进先出,后进后出
    

    1.2.1 GCD的使用 - 任务

    任务的执行:
    有两个函数来执行任务:
    - 同步
    - 异步
    
    说明:把右边的参数(任务)dispatch_block_t block
         提交给左边的参数(队列)dispatch_queue_t queue 进行执行。
    

    (1)任务的执行:同步

    //queue:队列    block:任务
    dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
    

    (2)任务的执行:异步

    • 函数1
    //queue:队列    block:任务
    dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
    
    • 函数2
    // 在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
    dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
    

    【区别】同步 & 异步:同步和异步决定了要不要开启新的线程
    - 同步:只能在当前线程中执行任务,不具备开启新线程的能力
    - 异步:可以在新的线程中执行任务,具备开启新线程的能力
    

    【区别】并发 & 串行:并发和串行决定了任务的执行方式
    - 并发:允许多个任务并发(同时)执行
    - 串行:一个任务执行完毕后,再执行下一个任务
    

    1.2.2 GCD的使用 - 队列

    队列分类:

    (1)并发队列(Concurrent Dispatch Queue)

    - 可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
    - 并发功能只有在异步(dispatch_async)函数下才有效
    

    (2)串行队列(Serial Dispatch Queue)

    - 让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
    

    release:
    - 凡是函数名种带有create\copy\new\retain等字眼, 都应该在不需要使用这个数据的时候进行release
    
    
    - GCD的数据类型在ARC环境下不需要再做release
    
      dispatch_release(queue); // 非ARC需要释放手动创建的队列
    
    
    - CF(Core Foundation)的数据类型在ARC环境下还是需要再做release
    

    队列名称的作用:
    将来调试的时候,可以看得出任务是在哪个队列中执行的。
    
    队列名称的作用.png

    1.2.2.1 创建队列 - 并发队列

    并行队列中的任务是多个任务同时执行的 :
    (1)如果异步任务前面有同步任务:
        - 就会先执行同步任务同步任务是按顺序执行的任务等他执行完了才会执行并行中的异步任务  
        -(可以做到阻塞 控制任务的执行顺序)
    
    (2)如果异步任务后面有同步任务:
         - 两个任务会并行(同时)执行
    
    方式1 - 手动创建并发队列:
    dispatch_queue_create(
        constchar *label,           // 队列名称
        dispatch_queue_attr_t attr  // 队列的类型
    );
    
    // 1.创建并发队列   DISPATCH_QUEUE_CONCURRENT (并发)
    dispatch_queue_t queue = dispatch_queue_create(“TD", DISPATCH_QUEUE_CONCURRENT);
    
    // 2.非ARC需要释放手动创建的队列
    dispatch_release(queue);
    
    方式2 - 获取全局并发队列:(GCD默认已经提供了全局的并发队列,供整个应用使用,可以无需手动创建)

    Xcode 7.2定义方式:

    dispatch_get_global_queue(
           long identifier,    // 队列的优先级
           unsignedlong flags  // 此参数暂时无用,用0即可
    );
    

    全局并发队列的优先级:(级别由高到低)

    #define DISPATCH_QUEUE_PRIORITY_HIGH 2               // 高
    #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0            // 默认(中)
    #define DISPATCH_QUEUE_PRIORITY_LOW (-2)             // 低
    #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
    
    // 获取全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    

    【代码】同步 + 并发

    在实际开发中,同步任务可以保证执行完成之后,才让后续的异步任务开始执行,用于控制任务之间的先后顺序,在后台线程中,处理“用户登录”

    代码示例:

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
      [super viewDidLoad];
      // Do any additional setup after loading the view, typically from a nib.
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
      [self syncConcurrent];
    }
    
    #pragma mark - 同步函数 + 并发队列:不会开启新的线程,在当前线程执行任务(主线程),顺序执行,并发队列失去了并发的功能
    - (void)syncConcurrent {
      NSLog(@"同步并发 ----- begin");
    
      // 1.获得全局的并发队列
      dispatch_queue_t queue =
          dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
      // 2.将任务加入队列
      dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
      });
      dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
      });
      dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
      });
    
      NSLog(@"同步并发 ----- end");
    }
    
    #pragma mark - 写法2
    - (void)concurrentSync {
      // 1. 创建并发队列
      dispatch_queue_t conCurrentQueue =
          dispatch_queue_create("TD", DISPATCH_QUEUE_CONCURRENT);
    
      // 2. 创建任务
      void (^task1)() = ^() {
        NSLog(@"---task1---%@", [NSThread currentThread]);
      };
    
      void (^task2)() = ^() {
        NSLog(@"---task2---%@", [NSThread currentThread]);
      };
    
      void (^task3)() = ^() {
        NSLog(@"---task3---%@", [NSThread currentThread]);
      };
    
      // 3. 将同步任务添加到并发队列中
      dispatch_sync(conCurrentQueue, task1);
      dispatch_sync(conCurrentQueue, task2);
      dispatch_sync(conCurrentQueue, task3);
    }
    
    - (void)didReceiveMemoryWarning {
      [super didReceiveMemoryWarning];
      // Dispose of any resources that can be recreated.
    }
    
    @end
    

    打印结果:

    同步并发[1702:246074] 同步并发 ----- begin
    同步并发[1702:246074] 1-----<NSThread: 0x7fe963d07360>{number = 1, name = main}
    同步并发[1702:246074] 2-----<NSThread: 0x7fe963d07360>{number = 1, name = main}
    同步并发[1702:246074] 3-----<NSThread: 0x7fe963d07360>{number = 1, name = main}
    同步并发[1702:246074] 同步并发 ----- end
    
    同步并发[1724:247291] ---task1---<NSThread: 0x7f8e71400d20>{number = 1, name = main}
    同步并发[1724:247291] ---task2---<NSThread: 0x7f8e71400d20>{number = 1, name = main}
    同步并发[1724:247291] ---task3---<NSThread: 0x7f8e71400d20>{number = 1, name = main}
    

    【代码】异步 + 并发

    代码示例:

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
      [super viewDidLoad];
      // Do any additional setup after loading the view, typically from a nib.
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
      [self asyncConcurrent];
    }
    
    #pragma mark - 异步函数 + 并发队列:可以同时开启多条线程,在当前线程执行任务(主线程),无序执行(按照任务添加到队列中的顺序被调度),线程条数具体由`可调度线程池/底层线程池`来决定
    - (void)asyncConcurrent {
      NSLog(@"异步并发 ----- begin");
    
      // 1.获得全局的并发队列
      dispatch_queue_t queue =
          dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
      // 2.将任务加入队列
      dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
      });
      dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
      });
      dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
      });
    
      NSLog(@"异步并发 ----- begin");
    }
    
    #pragma mark - 写法2
    - (void)concurrentAsync {
      // 1.创建并发队列
      dispatch_queue_t conCurrentQueue =
          dispatch_queue_create("TD", DISPATCH_QUEUE_CONCURRENT);
    
      // 2. 创建任务
      void (^task1)() = ^() {
        NSLog(@"---task1---%@", [NSThread currentThread]);
      };
    
      void (^task2)() = ^() {
        NSLog(@"---task2---%@", [NSThread currentThread]);
      };
    
      void (^task3)() = ^() {
        NSLog(@"---task3---%@", [NSThread currentThread]);
      };
    
      // 3. 将异步任务添加到并发队列中
      dispatch_async(conCurrentQueue, task1);
      dispatch_async(conCurrentQueue, task2);
      dispatch_async(conCurrentQueue, task3);
    }
    
    - (void)didReceiveMemoryWarning {
      [super didReceiveMemoryWarning];
      // Dispose of any resources that can be recreated.
    }
    
    @end
    

    打印结果:

    异步并发[1879:254274] 异步并发 ----- begin
    异步并发[1879:254274] 1-----<NSThread: 0x7fd598d02490>{number = 1, name = main}
    异步并发[1879:254274] 2-----<NSThread: 0x7fd598d02490>{number = 1, name = main}
    异步并发[1879:254274] 3-----<NSThread: 0x7fd598d02490>{number = 1, name = main}
    异步并发[1879:254274] 异步并发 ----- begin
    
    异步并发[1945:260502] ---task2---<NSThread: 0x7fbf68d927b0>{number = 3, name = (null)}
    异步并发[1945:260628] ---task3---<NSThread: 0x7fbf68e24570>{number = 4, name = (null)}
    异步并发[1945:260503] ---task1---<NSThread: 0x7fbf68f15ae0>{number = 2, name = (null)}
    

    1.2.2.2 创建队列 - 串行队列

    手动创建串行队列:
    • 串行队列中的任务都是按顺序执行,谁在前就先执行谁
    • 主线程和子线程平等,一样谁在前选执行谁
    • 执行完一个才会执行下一个任务
    dispatch_queue_create(
        constchar *label,           // 队列名称
        dispatch_queue_attr_t attr  // 队列的类型
    );
    
    //1.创建串行队列
    
    //方式1:DISPATCH_QUEUE_SERIAL (串行)
    dispatch_queue_t queue = dispatch_queue_create(“TD", DISPATCH_QUEUE_SERIAL);
    
    //方式2:传 NULL
    dispatch_queue_t queue = dispatch_queue_create(“TD", NULL);
    
    // 2.非ARC需要释放手动创建的队列
    dispatch_release(queue);
    

    【代码】同步 + 串行
    • 串行队列中的任务都是按顺序执行,谁在前就先执行谁
    • 主线程和子线程平等,一样谁在前选执行谁
    • 执行完一个才会执行下一个任务

    代码示例:

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
      [super viewDidLoad];
      // Do any additional setup after loading the view, typically from a nib.
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
      [self syncSerial];
    }
    
    #pragma mark - 同步函数 + 串行队列:不会开启新的线程,在当前线程执行任务(主线程),任务是串行的(顺序执行)
    - (void)syncSerial {
      NSLog(@"同步串行 ----- begin");
    
      // 1.创建串行队列
      dispatch_queue_t queue = dispatch_queue_create("TD", DISPATCH_QUEUE_SERIAL);
    
      // 2.将任务加入队列
      dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
      });
      dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
      });
      dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
      });
    
      NSLog(@"同步串行 ----- end");
    }
    
    #pragma mark - 写法2
    - (void)serialSyncDemo {
      // 1.创建队列
      dispatch_queue_t serialQueue =
          dispatch_queue_create("TD", DISPATCH_QUEUE_SERIAL);
    
      // 2.创建任务
      void (^task1)() = ^() {
        NSLog(@"task1---%@", [NSThread currentThread]);
      };
    
      void (^task2)() = ^() {
        NSLog(@"task2---%@", [NSThread currentThread]);
      };
    
      void (^task3)() = ^() {
        NSLog(@"task3---%@", [NSThread currentThread]);
      };
    
      // 3.将同步任务,添加到串行队列
      dispatch_sync(serialQueue, task3);
      dispatch_sync(serialQueue, task1);
      dispatch_sync(serialQueue, task2);
    }
    
    - (void)didReceiveMemoryWarning {
      [super didReceiveMemoryWarning];
      // Dispose of any resources that can be recreated.
    }
    
    @end
    

    打印结果:

    同步串行[2145:276628] 同步串行 ----- begin
    同步串行[2145:276628] 1-----<NSThread: 0x7fab52f04910>{number = 1, name = main}
    同步串行[2145:276628] 2-----<NSThread: 0x7fab52f04910>{number = 1, name = main}
    同步串行[2145:276628] 3-----<NSThread: 0x7fab52f04910>{number = 1, name = main}
    同步串行[2145:276628] 同步串行 ----- end
    
    同步串行[2248:284920] task1---<NSThread: 0x7fd910c05150>{number = 1, name = main}
    同步串行[2248:284920] task2---<NSThread: 0x7fd910c05150>{number = 1, name = main}
    同步串行[2248:284920] task3---<NSThread: 0x7fd910c05150>{number = 1, name = main}
    

    【代码】异步 + 串行
    • 串行队列中的任务都是按顺序执行,谁在前就先执行谁
    • 主线程和子线程平等,一样谁在前选执行谁
    • 执行完一个才会执行下一个任务

    串行队列,异步任务,在多线程中,是斯坦福大学最推荐的一种多线程方式!

    • 优点:将任务放在其他线程中工作,每个任务顺序执行,便于调试
    • 缺点:并发能力不强,最多只能使用一条线程!

    代码示例:

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
      [super viewDidLoad];
      // Do any additional setup after loading the view, typically from a nib.
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
      [self asyncSerial];
    }
    
    #pragma mark - 异步函数 + 串行队列:会开启新的线程,在子线程执行任务,任务是串行的(顺序执行),只开一条线程
    - (void)asyncSerial {
      NSLog(@"异步串行 ----- begin");
      NSLog(@"主线程  ----- %@", [NSThread mainThread]);
    
      // 1.创建串行队列
      //写法1:
      dispatch_queue_t queue = dispatch_queue_create("TD", DISPATCH_QUEUE_SERIAL);
      //写法2:
      dispatch_queue_t queue = dispatch_queue_create("TD", NULL);
    
      // 2.将任务加入队列
      dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
      });
      dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
      });
      dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
      });
    
      NSLog(@"异步串行 ----- end");
    }
    
    #pragma mark - 写法2
    - (void)serialAsyncDemo {
      // 1.创建队列
      dispatch_queue_t serialQueue =
          dispatch_queue_create("TD", DISPATCH_QUEUE_SERIAL);
    
      // 2.创建任务
      void (^task1)() = ^() {
        NSLog(@"task1---%@", [NSThread currentThread]);
      };
    
      void (^task2)() = ^() {
        NSLog(@"task2---%@", [NSThread currentThread]);
      };
    
      void (^task3)() = ^() {
        NSLog(@"task3---%@", [NSThread currentThread]);
      };
    
      // 3.将异步任务添加到串行队列
      dispatch_async(serialQueue, task1);
      dispatch_async(serialQueue, task2);
      dispatch_async(serialQueue, task3);
    }
    
    - (void)didReceiveMemoryWarning {
      [super didReceiveMemoryWarning];
      // Dispose of any resources that can be recreated.
    }
    
    @end
    

    打印结果:

    异步串行[2486:297960] 异步串行 ----- begin
    异步串行[2486:297960]主线程  ----- <NSThread: 0x7ff271701ba0>{number = 1, name = main}
    异步串行[2486:297960]异步串行----- end
    异步串行[2486:298011] 1-----<NSThread: 0x7ff2717abb30>{number = 2, name = (null)}
    异步串行[2486:298011] 2-----<NSThread: 0x7ff2717abb30>{number = 2, name = (null)}
    异步串行[2486:298011] 3-----<NSThread: 0x7ff2717abb30>{number = 2, name = (null)}
    
    异步串行[2529:301017] task1---<NSThread: 0x7fddb9405f40>{number = 2, name = (null)}
    异步串行[2529:301017] task2---<NSThread: 0x7fddb9405f40>{number = 2, name = (null)}
    异步串行[2529:301017] task3---<NSThread: 0x7fddb9405f40>{number = 2, name = (null)}
    

    1.2.2.3 创建队列 - 主队列(特殊的串行队列)

    主队列(跟主线程相关联的队列):
    • 主队列是GCD自带的一种特殊的串行队列
    • 放在主队列中的任务,都会放到主线程中执行
    • 如果把任务放到主队列中进行处理,那么不论处理函数是异步的还是同步的都不会开启新的线程。
    • 主队列中不能用同步任务,无论是在异步任务前还是后都会死锁

    获取主队列:
    dispatch_get_main_queue(void);
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    

    【代码】同步 + 主队列

    主队列中不能用同步任务,无论是在异步任务前还是后都会死锁


    代码示例:

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
      [super viewDidLoad];
      // Do any additional setup after loading the view, typically from a nib.
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
      [self syncMain];
    }
    
    #pragma mark - 同步函数 + 主队列:不会开启新的线程,会出现"死等",可能导致`主线程`卡死
    - (void)syncMain {
      NSLog(@"同步主队列 ----- begin");
    
      // 1.获得主队列
      dispatch_queue_t queue = dispatch_get_main_queue();
    
      // 2.将任务加入队列
      dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
      });
      dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
      });
      dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
      });
    
      NSLog(@"同步主队列 ----- end");
    }
    
    - (void)mainQueueSync {
      NSLog(@"同步主队列 ----- begin");
    
      // 1.获取主队列
      dispatch_queue_t mainQueue = dispatch_get_main_queue();
    
      // 2.创建队列
      void (^task1)() = ^() {
        NSLog(@"---task1---%@", [NSThread currentThread]);
      };
    
      void (^task2)() = ^() {
        NSLog(@"---task2---%@", [NSThread currentThread]);
      };
    
      void (^task3)() = ^() {
        NSLog(@"---task3---%@", [NSThread currentThread]);
      };
    
      // 3.将同步任务添加到并发队列中
      dispatch_sync(mainQueue, task1);
      dispatch_sync(mainQueue, task2);
      dispatch_sync(mainQueue, task3);
    
      NSLog(@"同步主队列 ----- end");
    }
    
    - (void)didReceiveMemoryWarning {
      [super didReceiveMemoryWarning];
      // Dispose of any resources that can be recreated.
    }
    
    @end
    

    打印结果:

    同步主队列[3286:329220] 同步主队列 ----- begin
    

    【代码】异步 + 主队列

    代码示例:

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
      [super viewDidLoad];
      // Do any additional setup after loading the view, typically from a nib.
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
      [self asyncMain];
    }
    
    #pragma mark -  异步函数 + 主队列:不会开启新的线程,在当前线程执行任务(主线程),任务是串行的(顺序执行),只开一条线程(适合处理 UI 或者是 UI事件)
    - (void)asyncMain {
      NSLog(@"异步主队列 ----- begin");
    
      // 1.获得主队列
      dispatch_queue_t queue = dispatch_get_main_queue();
    
      // 2.将任务加入队列
      dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
      });
      dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
      });
      dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
      });
    
      NSLog(@"异步主队列 ----- end");
    }
    
    #pragma mark - 写法2
    - (void)mainQueueAsync {
      NSLog(@"异步主队列 ----- begin");
    
      // 1.获取主队列
      dispatch_queue_t mainQueue = dispatch_get_main_queue();
    
      // 2.创建任务
      void (^task1)() = ^() {
        NSLog(@"---async task1---%@", [NSThread currentThread]);
      };
    
      void (^task2)() = ^() {
        NSLog(@"---async task2---%@", [NSThread currentThread]);
      };
    
      void (^task3)() = ^() {
        NSLog(@"---async task3---%@", [NSThread currentThread]);
      };
    
      // 3.将异步任务添加到主队列中
      dispatch_async(mainQueue, task1);
      dispatch_async(mainQueue, task2);
      dispatch_async(mainQueue, task3);
    
      NSLog(@"异步主队列 ----- end");
    }
    
    - (void)didReceiveMemoryWarning {
      [super didReceiveMemoryWarning];
      // Dispose of any resources that can be recreated.
    }
    
    @end
    

    打印结果:

    异步主队列[2949:318506] 异步主队列 ----- begin
    异步主队列[2949:318506]异步主队列----- end
    异步主队列[2949:318506] 1-----<NSThread: 0x7feec9c082e0>{number = 1, name = main}
    异步主队列[2949:318506] 2-----<NSThread: 0x7feec9c082e0>{number = 1, name = main}
    异步主队列[2949:318506] 3-----<NSThread: 0x7feec9c082e0>{number = 1, name = main}
    
    异步主队列[2970:319219] 异步主队列 ----- begin
    异步主队列[2970:319219]异步主队列----- end
    异步主队列[2970:319219] ---async task1---<NSThread: 0x7f9de1c074e0>{number = 1, name = main}
    异步主队列[2970:319219] ---async task2---<NSThread: 0x7f9de1c074e0>{number = 1, name = main}
    异步主队列[2970:319219] ---async task3---<NSThread: 0x7f9de1c074e0>{number = 1, name = main}
    

    1.2.2.4 总结

    GCD 队列类型的创建方式:
    • 并发队列:手动创建、全局
    • 串行队列:手动创建、主队列

    各种队列的执行效果

    注意:使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列(比如同步主队列)


    同步函数 + 并发队列:不会开启新的线程,在当前线程执行任务(主线程),顺序执行,并发队列失去了并发的功能


    #######异步函数 + 并发队列:可以同时开启多条线程,在当前线程执行任务(主线程),无序执行(按照任务添加到队列中的顺序被调度),线程条数具体由可调度线程池/底层线程池来决定


    并行队列中的任务是多个任务同时执行的 :

    (1)如果异步任务前面有同步任务:就会先执行同步任务同步任务是按顺序执行的任务等他执行完了才会执行并行中的异步任务  (可以做到阻塞 控制任务的执行顺序)
    
    (2)如果异步任务后面有同步任务:两个任务会并行(同时)执行
    

    同步函数 + 串行队列:不会开启新的线程,在当前线程执行任务(主线程),任务是串行的(顺序执行)


    异步函数 + 串行队列:会开启新的线程,在子线程执行任务,任务是串行的(顺序执行),只开一条线程


    串行队列中的任务都是按顺序执行:

    - 串行队列中的任务都是按顺序执行,谁在前就先执行谁
    - 主线程和子线程平等,一样谁在前选执行谁
    - 执行完一个才会执行下一个任务
    

    串行队列,异步任务,在多线程中,是斯坦福大学最推荐的一种多线程方式!

    - 优点:将任务放在其他线程中工作,每个任务顺序执行,便于调试
    - 缺点:并发能力不强,最多只能使用一条线程!
    

    异步函数 + 主队列:不会开启新的线程,在当前线程执行任务(主线程),任务是串行的(顺序执行),只开一条线程(适合处理 UI 或者是 UI事件)


    同步函数 + 主队列:不会开启新的线程,会出现"死等",可能导致主线程卡死


    主队列中不能用同步任务,无论是在异步任务前还是后都会死锁


    【区别】同步 & 异步:同步和异步决定了要不要开启新的线程
    - 同步:只能在当前线程中执行任务,不具备开启新线程的能力
    
    - 异步:可以在新的线程中执行任务,具备开启新线程的能力
    
    【区别】并发 & 串行:并发和串行决定了任务的执行方式
    - 并发:允许多个任务并发(同时)执行
    
    - 串行:一个任务执行完毕后,再执行下一个任务
    
    同步函数:无论是什么队列都不会开启线程
    (1)并发队列:不会开线程
    (2)串行队列:不会开线程
    
    异步函数:具备开启线程的能力(但不一定会开线程 ),开启几条线程由队列决定
    (1)并发队列:能开启N条线程
    (2)串行队列:开启1条线程
    

    本文源码 Demo 详见 Github
    https://github.com/shorfng/iOS_4.0_multithreading.git




    作者:蓝田(Loto)
    出处: 简书

    如果你觉得本篇文章对你有所帮助,请点击文章末尾下方“喜欢”
    如有疑问,请通过以下方式交流:
    评论区回复微信(加好友请注明“简书+称呼”)发送邮件shorfng@126.com



    本文版权归作者和本网站共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

    相关文章

      网友评论

      本文标题:4.4 GCD->1.0 GCD简介和使用

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