zoukankan      html  css  js  c++  java
  • 多线程 -- GCD

    • GCD中有2个核心概念

      • 任务:执行什么操作
      • 队列:用来存放任务
    • 执行任务

      • 同步方法: dispatch_sync
        dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
        queue:队列
        block:任务
        
      • 异步方法: dispatch_async
        dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
      • 同步和异步的区别
        • 同步:只能在当前线程中执行任务,不具备开启新线程的能力
        • 异步:可以在新的线程中执行任务,具备开启新线程的能力
    • 队列

      • 并发队列
        • 可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
        • 并发功能只有在异步(dispatch_async)函数下才有效
      • 串行队列
        • 让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
    • 注意点

      • 同步和异步主要影响:能不能开启新的线程
        • 同步:只是在当前线程中执行任务,不具备开启新线程的能力
        • 异步:可以在新的线程中执行任务,具备开启新线程的能力
      • 并发和串行主要影响:任务的执行方式
        • 并发:允许多个任务并发(同时)执行
        • 串行:一个任务执行完毕后,再执行下一个任务
    • 各种任务队列搭配

      • 同步 + 串行 
      • /*
         同步 + 串行: 不会开启新的线程
         注意点: 如果是调用 同步函数, 那么会等同步函数中的任务执行完毕, 才会执行后面的代码
         */
        - (void)syncSerial
        {
            // 1.创建一个串行队列
            // #define DISPATCH_QUEUE_SERIAL NULL
            // 所以可以直接传NULL
            dispatch_queue_t queue = dispatch_queue_create("com.520it.lnj", NULL);
            
            // 2.将任务添加到队列中
            dispatch_sync(queue, ^{
                NSLog(@"任务1  == %@", [NSThread currentThread]);
            });
            dispatch_sync(queue, ^{
                NSLog(@"任务2  == %@", [NSThread currentThread]);
            });
            dispatch_sync(queue, ^{
                NSLog(@"任务3  == %@", [NSThread currentThread]);
            });
            
            NSLog(@"---------");
        }
      • 同步 + 并发 *
        /*
         同步 + 并发 : 不会开启新的线程
         妻管严
         */
        - (void)syncConCurrent
        {
            // 1.创建一个并发队列
            dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
            
            // 2.将任务添加到队列中
            dispatch_sync(queue, ^{
                NSLog(@"任务1  == %@", [NSThread currentThread]);
            });
            dispatch_sync(queue, ^{
                NSLog(@"任务2  == %@", [NSThread currentThread]);
            });
            dispatch_sync(queue, ^{
                NSLog(@"任务3  == %@", [NSThread currentThread]);
            });
            
             NSLog(@"---------");
        }
      • 异步 + 串行 *
        /*
         异步 + 串行:会开启新的线程
        但是只会开启一个新的线程
         注意: 如果调用 异步函数, 那么不用等到函数中的任务执行完毕, 就会执行后面的代码
         */
        - (void)asynSerial
        {
            // 1.创建串行队列
            dispatch_queue_t queue = dispatch_queue_create("com.520it.lnj", DISPATCH_QUEUE_SERIAL);
            /*
             能够创建新线程的原因:
             我们是使用"异步"函数调用
             只创建1个子线程的原因:
             我们的队列是串行队列
             */
            // 2.将任务添加到队列中
            dispatch_async(queue, ^{
                NSLog(@"任务1  == %@", [NSThread currentThread]);
            });
            dispatch_async(queue, ^{
                NSLog(@"任务2  == %@", [NSThread currentThread]);
            });
            dispatch_async(queue, ^{
                NSLog(@"任务3  == %@", [NSThread currentThread]);
            });
            
            NSLog(@"--------");
        }
      • 异步 + 并发 *
        /*
         异步 + 并发 : 会开启新的线程
         如果任务比较多, 那么就会开启多个线程
         */
        - (void)asynConcurrent
        {
            /*
             执行任务
             dispatch_async
             dispatch_sync
             */
            
            /*
             第一个参数: 队列的名称
             第二个参数: 告诉系统需要创建一个并发队列还是串行队列
             DISPATCH_QUEUE_SERIAL :串行
             DISPATCH_QUEUE_CONCURRENT 并发
             */
            //    dispatch_queue_t queue = dispatch_queue_create("com.520it.lnj", DISPATCH_QUEUE_CONCURRENT);
            
            // 系统内部已经给我们提供好了一个现成的并发队列
            /*
             第一个参数: iOS8以前是优先级, iOS8以后是服务质量
             iOS8以前
             *  - DISPATCH_QUEUE_PRIORITY_HIGH          高优先级 2
             *  - DISPATCH_QUEUE_PRIORITY_DEFAULT:      默认的优先级 0
             *  - DISPATCH_QUEUE_PRIORITY_LOW:          低优先级 -2
             *  - DISPATCH_QUEUE_PRIORITY_BACKGROUND:
             
             iOS8以后
             *  - QOS_CLASS_USER_INTERACTIVE  0x21 用户交互(用户迫切想执行任务)
             *  - QOS_CLASS_USER_INITIATED    0x19 用户需要
             *  - QOS_CLASS_DEFAULT           0x15 默认
             *  - QOS_CLASS_UTILITY           0x11 工具(低优先级, 苹果推荐将耗时操作放到这种类型的队列中)
             *  - QOS_CLASS_BACKGROUND        0x09 后台
             *  - QOS_CLASS_UNSPECIFIED       0x00 没有设置
             
             第二个参数: 废物
             */
            dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
            
            /*
             第一个参数: 用于存放任务的队列
             第二个参数: 任务(block)
             
             GCD从队列中取出任务, 遵循FIFO原则 , 先进先出
             输出的结果和苹果所说的原则不符合的原因: CPU可能会先调度其它的线程
             
             能够创建新线程的原因:
             我们是使用"异步"函数调用
             能够创建多个子线程的原因:
             我们的队列是并发队列
             */
            dispatch_async(queue, ^{
                NSLog(@"任务1  == %@", [NSThread currentThread]);
            });
            dispatch_async(queue, ^{
                NSLog(@"任务2  == %@", [NSThread currentThread]);
            });
            dispatch_async(queue, ^{
                NSLog(@"任务3  == %@", [NSThread currentThread]);
            });
        }
      • 异步 + 主队列 *
         异步 + 主队列 : 不会创建新的线程, 并且任务是在主线程中执行
         */
        - (void)asyncMain
        {
            // 主队列:
            // 特点: 只要将任务添加到主队列中, 那么任务"一定"会在主线程中执行 
            无论你是调用同步函数还是异步函数
            dispatch_queue_t queue = dispatch_get_main_queue();
            
            dispatch_async(queue, ^{
                NSLog(@"%@", [NSThread currentThread]);
            });
        }
      • 同步 + 主队列 *
        /*
         如果是在主线程中调用同步函数 + 主队列, 那么会导致死锁
         导致死锁的原因:
         sync函数是在主线程中执行的, 并且会等待block执行完毕. 先调用
         block是添加到主队列的, 也需要在主线程中执行. 后调用
         */
        - (void)syncMain
        {
            NSLog(@"%@", [NSThread currentThread]);
            // 主队列:
            dispatch_queue_t queue = dispatch_get_main_queue();
            
            //  如果是调用 同步函数, 那么会等同步函数中的任务执行完毕, 才会执行后面的代码
            // 注意: 如果dispatch_sync方法是在主线程中调用的, 并且传入的队列是主队列, 那么会导致死锁
            dispatch_sync(queue, ^{
                NSLog(@"----------");
                NSLog(@"%@", [NSThread currentThread]);
            });
            NSLog(@"----------");
        }
    • GCD线程间通信

    dispatch_async(
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 执行耗时的异步操作...
          dispatch_async(dispatch_get_main_queue(), ^{
            // 回到主线程,执行UI刷新操作
            });
    });
    • GCD其它用法
    • 延时执行
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 2秒后执行这里的代码...
    });
    • 一次性代码
      • 使用dispatch_once函数能保证某段代码在程序运行过程中只被执行1次
      •  static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ 

        // 只执行1次的代码(这里面默认是线程安全的)

        });
    
    - 快速迭代
    
    dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index){
        // 执行10次代码,index顺序不确定
    });
    • barrier (栅栏)
      • 在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
      • 不能是全局的并发队列
      • 所有的任务都必须在一个队列中
    dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
    • 队列组
    dispatch_group_t group =  dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 执行1个耗时的异步操作
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 执行1个耗时的异步操作
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 等前面的异步操作都执行完毕后,回到主线程...
    });
    本博文由博主根据资料或其他优秀博文整理而成,转载请注明出处,谢谢!
  • 相关阅读:
    领域模型(domain model)&贫血模型(anaemic domain model)&充血模型(rich domain model)
    XSS攻击&SQL注入攻击&CSRF攻击?
    算法笔记_054:Prim算法(Java)
    算法笔记_053:最优二叉查找树(Java)
    算法笔记_052:蓝桥杯练习Multithreading(Java)
    算法笔记_051:荷兰国旗问题(Java)
    算法笔记_050:硬币收集问题(Java)
    算法笔记_049:奇偶数排序(Java)
    算法笔记_048:找零问题(Java)
    算法笔记_047:复数运算(Java)
  • 原文地址:https://www.cnblogs.com/Apolla/p/4737957.html
Copyright © 2011-2022 走看看