多线程 - 07.GCD函数和队列组合示例

来源:互联网 发布:js中get post 区别 编辑:程序博客网 时间:2024/06/06 11:41

1.GCD基本使用(异步函数+并发队列)

  • 可以看到,系统自动给开辟了新的子线程来执行这三个任务,且由于时并发队列,系统开辟了三个子线程
  • 注意:开辟多少个子线程由系统决定,三个任务依次从队列中取出放在不同的子线程执行,但是由于CPU调度子线程是由系统控制的,所以任务执行的顺序不定,并没有违背队列中任务的先进先出原则
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    // 1.创建队列    /* 参数解释     第一个参数:队列名称     第二个参数:队列属性(串行还是并发)     DISPATCH_QUEUE_SERIAL :串行     DISPATCH_QUEUE_CONCURRENT 并发     */    // 1.1创建一个并发队列//    dispatch_queue_t queue = dispatch_queue_create("zj.queue", DISPATCH_QUEUE_CONCURRENT);    // 1.2系统内部已经给我们提供好了一个现成的并发队列    /*     第一个参数: 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 没有设置     第二个参数: Flags that are reserved for future use. Always specify 0 for this parameter.     根据苹果文档,可以知道这是一个保留值,以便苹果在系统内部执行一些操作,并且苹果建议我们始终传入0即可.     */     // 为了同时适配iOS8以及iOS8以前的版本,优先级参数直接传0即可    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);    // 2.添加任务到队列(这里使用异步方式)    /* 参数解释     第一个参数:需要将任务添加到哪个队列     第二个参数:需要执行的任务     */    // 连续添加三个任务    dispatch_async(queue, ^{        NSLog(@"%@",[NSThread currentThread]);    });    dispatch_async(queue, ^{        NSLog(@"%@",[NSThread currentThread]);    });    dispatch_async(queue, ^{        NSLog(@"%@",[NSThread currentThread]);    });    /* 结果:(每次打印的线程number顺序不一致)     <NSThread: 0x7fb878d02110>{number = 4, name = (null)}     <NSThread: 0x7fb878e21500>{number = 3, name = (null)}     <NSThread: 0x7fb878f91e20>{number = 2, name = (null)}     */}

2.GCD基本使用(异步函数+串行队列)

  • 可以看到,开启了新的线程,但是只开启了一条
  • 能够创建新线程的原因:使用”异步”函数调用
  • 只创建1个子线程的原因:队列是串行队列
  • 由于队列串行队列,所以任务是从上到下依次执行
  • 由于使用了异步函数,那么不会等到异步函数中的任务执行完毕再去执行后面的代码
- (void)asynSerial{    // 1.创建串行队列    dispatch_queue_t queue = dispatch_queue_create("zj.queue", DISPATCH_QUEUE_SERIAL);    // 2.添加任务到队列    // 连续添加三个任务    dispatch_async(queue, ^{        NSLog(@"任务一执行,%@",[NSThread currentThread]);    });    dispatch_async(queue, ^{        NSLog(@"任务二执行,%@",[NSThread currentThread]);    });    dispatch_async(queue, ^{        NSLog(@"任务三执行,%@",[NSThread currentThread]);    });    NSLog(@"+++++++");    /* 打印结果:     任务一执行,<NSThread: 0x7fdb91720450>{number = 2, name = (null)}     +++++++     任务二执行,<NSThread: 0x7fdb91720450>{number = 2, name = (null)}     任务三执行,<NSThread: 0x7fdb91720450>{number = 2, name = (null)}     */}

3.GCD基本使用(同步函数+串行队列)

  • 可以看到不会开启新的线程,且线程中的任务会依次执行
  • 因为调用了同步函数, 那么会等同步函数中的任务执行完毕, 才会执行后面的代码
- (void)syncSerial{    // 1.创建一个串行队列    // #define DISPATCH_QUEUE_SERIAL NULL    // 所以可以直接传NULL    dispatch_queue_t queue = dispatch_queue_create("zj.queue", NULL);    // 2.将任务添加到队列中    dispatch_sync(queue, ^{        NSLog(@"任务1  == %@", [NSThread currentThread]);    });    dispatch_sync(queue, ^{        NSLog(@"任务2  == %@", [NSThread currentThread]);    });    dispatch_sync(queue, ^{        NSLog(@"任务3  == %@", [NSThread currentThread]);    });    NSLog(@"---------");    /*输出结果:     任务1  == <NSThread: 0x7fe129512690>{number = 1, name = main}     任务2  == <NSThread: 0x7fe129512690>{number = 1, name = main}     任务3  == <NSThread: 0x7fe129512690>{number = 1, name = main}     ---------     */}

4.GCD基本使用(同步函数+并发队列)

  • 使用了同步函数,不会创建新的线程
/* 同步 + 并发 : 不会开启新的线程 */- (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(@"---------");    /*输出结果:     任务1  == <NSThread: 0x7fe129512690>{number = 1, name = main}     任务2  == <NSThread: 0x7fe129512690>{number = 1, name = main}     任务3  == <NSThread: 0x7fe129512690>{number = 1, name = main}     ---------     */}

5.GCD基本使用(异步函数+主队列)

  • 只要是在主队列,那么无论是调用同步还是异步函数,都不会开启新线程,一定会在主线程中执行
/* 异步 + 主队列 : 不会创建新的线程,并且任务是在主线程中执行 */- (void)asyncMain{    // 创建主队列    dispatch_queue_t queue = dispatch_get_main_queue();    dispatch_async(queue, ^{        NSLog(@"%@", [NSThread currentThread]);    });    dispatch_async(queue, ^{        NSLog(@"%@", [NSThread currentThread]);    });}    /* 输出结果:     任务一 <NSThread: 0x7fa1d35267c0>{number = 1, name = main}     任务二 <NSThread: 0x7fa1d35267c0>{number = 1, name = main}     */

6.GCD基本使用(同步函数+主队列)-死锁

  • 如果是在主线程中调用同步函数 + 主队列, 那么会导致死锁
    导致死锁的原因:
    • sync函数是在主线程中执行的, 并且会等待block执行完毕. 先调用
    • block是添加到主队列的, 也需要在主线程中执行. 后调用
    • 由于队列的先进先出原则,那么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(@"----------");}/* 输出结果:队列中的任务以及主线程中后续的操作不再执行<NSThread: 0x7fadbad1ba70>{number = 1, name = main}*/

7.GCD基本使用(同步函数+主队列)-不死锁

  • 要想使用同步函数和主队列,且不造成死锁,可以在子线程中执行同步函数
/* 如果是在子线程中调用 同步函数 + 主队列, 那么没有任何问题 */- (void)syncMain2{    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);    dispatch_async(queue, ^{        // block会在子线程中执行        //        NSLog(@"%@", [NSThread currentThread]);        dispatch_queue_t queue = dispatch_get_main_queue();        dispatch_sync(queue, ^{            // block一定会在主线程执行            NSLog(@"%@", [NSThread currentThread]);        });    });    NSLog(@"------------");    /* 输出结果:     ------------     <NSThread: 0x7fd16af280d0>{number = 1, name = main}     */}
0 0
原创粉丝点击