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

iOS-GCD的理解与使用

程序员文章站 2022-06-22 17:27:45
一、任务和队列任务:在线程中执行的操作;执行任务有两种方式:同步执行 和 异步执行:同步执行:同步添加任务到队列中,前一个任务没有执行完,后面不能执行。不开辟新线程异步执行:异步添加任务到队列中,任务同一时间可以一起执行。开启多个新线程队列:队列是一种特殊的线性表,采用 FIFO(先进先出)的原则;GCD中有两种队列:串行队列和并发队列:串行队列:每次只有一个任务被执行,让任务一个接着一个地执行并发队列:可以让多个任务并发(同时)执行二、队列和任务的创建1、队列使用dispatc...

一、任务和队列

任务:在线程中执行的操作;执行任务有两种方式:同步执行异步执行

  • 同步执行:同步添加任务到队列中,前一个任务没有执行完,后面不能执行。不开辟新线程
  • 异步执行:异步添加任务到队列中,任务同一时间可以一起执行。开启多个新线程

队列:队列是一种特殊的线性表,采用 FIFO(先进先出)的原则;GCD中有两种队列:串行队列并发队列

  • 串行队列:每次只有一个任务被执行,让任务一个接着一个地执行
  • 并发队列:可以让多个任务并发(同时)执行

二、队列和任务的创建

1、队列

  • 使用dispatch_queue_create来创建队列对象
// 串行队列
dispatch_queue_t queue = dispatch_queue_create("com.test", DISPATCH_QUEUE_SERIAL);
// 并发队列
dispatch_queue_t queue1 = dispatch_queue_create("com.test", DISPATCH_QUEUE_CONCURRENT);

特殊队列:
主队列dispatch_get_main_queue() 实质上就是一个普通的串行队列,负责在主线程上调度任务,通常是返回主线程更新UI的时候使用

// 主队列
dispatch_queue_t queue = dispatch_get_main_queue();

全局并发队列dispatch_get_global_queue 全局并发队列是就是一个并发队列,是为了让我们更方便的使用多线程

// 全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

2、任务

  • 同步执行任务创建:dispatch_sync
  • 异步执行任务创建:dispatch_async
// 同步执行任务创建
dispatch_sync(queue, ^{
    // 执行任务代码
});
// 异步执行任务创建
dispatch_async(queue, ^{
    // 执行任务代码
});

三、GCD的使用

GCD 有两种队列(串行队列 / 并发队列),两种任务执行方式(同步执行 / 异步执行),那么就有了四种不同的组合方式:同步执行 + 串行队列、同步执行 + 并发队列、异步执行 + 串行队列、异步执行 + 并发队列
除了以上四种组合,我们还有两种特殊队列,全局并发队列可以作为普通并发队列来使用可忽略;主队列是特殊的串行队列,需要注意一下;这样就多处两种不同的组合:同步执行 + 主队列、 异步执行 + 主队列

下面来看看不同组合方式的区别:

任务 串行队列 并发队列 主队列
同步 没有开启新线程,串行执行任务 没有开启新线程,串行执行任务 死锁
异步 开启1条新线程,串行执行任务 开启新线程,并发执行任务 没有开启新线程,串行执行任务

1、组合方式

  • 串行同步

不会开启新线程,执行完一个任务,再执行下一个任务。

- (void)syncSerial {
    // 串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.test", DISPATCH_QUEUE_SERIAL);

    // 同步执行
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"串行同步1   %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"串行同步2   %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"串行同步3   %@",[NSThread currentThread]);
        }
    });
    
}

打印结果
2020-08-13 16:46:07.992056+0800 ModuleProject[16844:390970] 串行同步1   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.992250+0800 ModuleProject[16844:390970] 串行同步1   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.992372+0800 ModuleProject[16844:390970] 串行同步1   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.992509+0800 ModuleProject[16844:390970] 串行同步2   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.992804+0800 ModuleProject[16844:390970] 串行同步2   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.993153+0800 ModuleProject[16844:390970] 串行同步2   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.993301+0800 ModuleProject[16844:390970] 串行同步3   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.993401+0800 ModuleProject[16844:390970] 串行同步3   <NSThread: 0x6000011c0080>{number = 1, name = main}
2020-08-13 16:46:07.993536+0800 ModuleProject[16844:390970] 串行同步3   <NSThread: 0x6000011c0080>{number = 1, name = main}
  • 串行异步

开启新线程,任务是串行的,按顺序执行任务

- (void)asyncSerial {
    // 串行队列
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);

    // 同步执行
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"串行异步1   %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"串行异步2   %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"串行异步3   %@",[NSThread currentThread]);
        }
    });
    NSLog(@"结束  %@",[NSThread currentThread]);
}

打印结果
2020-08-13 17:04:14.468515+0800 ModuleProject[17093:404582] 结束  <NSThread: 0x600001c50400>{number = 1, name = main}
2020-08-13 17:04:14.468541+0800 ModuleProject[17093:404761] 串行异步1   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.468740+0800 ModuleProject[17093:404761] 串行异步1   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.468876+0800 ModuleProject[17093:404761] 串行异步1   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.468999+0800 ModuleProject[17093:404761] 串行异步2   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.469111+0800 ModuleProject[17093:404761] 串行异步2   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.469232+0800 ModuleProject[17093:404761] 串行异步2   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.469364+0800 ModuleProject[17093:404761] 串行异步3   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.470013+0800 ModuleProject[17093:404761] 串行异步3   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
2020-08-13 17:04:14.470304+0800 ModuleProject[17093:404761] 串行异步3   <NSThread: 0x600001c1ce40>{number = 4, name = (null)}
  • 并发同步

不会开启新线程,执行完一个任务,再执行下一个任务。

- (void)syncConcurrent {

    // 并发队列
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    // 同步执行
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"并发同步1   %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"并发同步2   %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"并发同步3   %@",[NSThread currentThread]);
        }
    });
    NSLog(@"结束  %@",[NSThread currentThread]);
}

打印结果
2020-08-13 17:22:39.528821+0800 ModuleProject[17314:418018] 并发同步1   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.528998+0800 ModuleProject[17314:418018] 并发同步1   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.529105+0800 ModuleProject[17314:418018] 并发同步1   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.529255+0800 ModuleProject[17314:418018] 并发同步2   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.529365+0800 ModuleProject[17314:418018] 并发同步2   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.529458+0800 ModuleProject[17314:418018] 并发同步2   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.529551+0800 ModuleProject[17314:418018] 并发同步3   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.529684+0800 ModuleProject[17314:418018] 并发同步3   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.530157+0800 ModuleProject[17314:418018] 并发同步3   <NSThread: 0x6000010608c0>{number = 1, name = main}
2020-08-13 17:22:39.530727+0800 ModuleProject[17314:418018] 结束  <NSThread: 0x6000010608c0>{number = 1, name = main}

  • 并发异步
    开启多线程,任务交替执行
- (void)asyncConcurrent {
        
    // 并发队列
    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    
    // 异步执行
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"并发异步1   %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"并发异步2   %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"并发异步3   %@",[NSThread currentThread]);
        }
    });
    NSLog(@"结束  %@",[NSThread currentThread]);
}

打印结果
2020-08-13 17:31:06.193967+0800 ModuleProject[17457:426793] 并发异步2   <NSThread: 0x60000176b800>{number = 4, name = (null)}
2020-08-13 17:31:06.193966+0800 ModuleProject[17457:426621] 结束  <NSThread: 0x60000174cec0>{number = 1, name = main}
2020-08-13 17:31:06.193991+0800 ModuleProject[17457:426795] 并发异步1   <NSThread: 0x60000176b580>{number = 3, name = (null)}
2020-08-13 17:31:06.194006+0800 ModuleProject[17457:426791] 并发异步3   <NSThread: 0x6000017186c0>{number = 6, name = (null)}
2020-08-13 17:31:06.194162+0800 ModuleProject[17457:426793] 并发异步2   <NSThread: 0x60000176b800>{number = 4, name = (null)}
2020-08-13 17:31:06.194162+0800 ModuleProject[17457:426795] 并发异步1   <NSThread: 0x60000176b580>{number = 3, name = (null)}
2020-08-13 17:31:06.194168+0800 ModuleProject[17457:426791] 并发异步3   <NSThread: 0x6000017186c0>{number = 6, name = (null)}
2020-08-13 17:31:06.194280+0800 ModuleProject[17457:426793] 并发异步2   <NSThread: 0x60000176b800>{number = 4, name = (null)}
2020-08-13 17:31:06.194305+0800 ModuleProject[17457:426795] 并发异步1   <NSThread: 0x60000176b580>{number = 3, name = (null)}
2020-08-13 17:31:06.194308+0800 ModuleProject[17457:426791] 并发异步3   <NSThread: 0x6000017186c0>{number = 6, name = (null)}
  • 主队列同步
    会发生死锁,程序崩溃。
    主队列同步,把任务放到了主线程的队列中。同步执行会等待当前队列中的任务执行完毕,才会接着执行。那么当我们把 任务 1 追加到主队列中,任务 1 就在等待主线程处理完 syncMain 任务。而syncMain 任务需要等待 任务 1 执行完毕,才能接着执行。现在的情况就是 syncMain 任务和 任务 1 都在等对方执行完毕产生死锁
- (void)syncMain {
    // 主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    // 崩溃
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"主队列同步1   %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"主队列同步2   %@",[NSThread currentThread]);
        }
    });
    NSLog(@"结束  %@",[NSThread currentThread]);
}
  • 主队列异步
    在主线程中任务按顺序执行
- (void)asyncMain {

    // 主队列
    dispatch_queue_t queue = dispatch_get_main_queue();

    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"主队列异步1   %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"主队列异步2   %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"主队列异步3   %@",[NSThread currentThread]);
        }
    });
    NSLog(@"结束  %@",[NSThread currentThread]);

}

打印结果
2020-08-13 17:53:06.936163+0800 ModuleProject[17714:442887] 结束  <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.029229+0800 ModuleProject[17714:442887] 主队列异步1   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.029465+0800 ModuleProject[17714:442887] 主队列异步1   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.029620+0800 ModuleProject[17714:442887] 主队列异步1   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.029767+0800 ModuleProject[17714:442887] 主队列异步2   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.029891+0800 ModuleProject[17714:442887] 主队列异步2   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.030031+0800 ModuleProject[17714:442887] 主队列异步2   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.030137+0800 ModuleProject[17714:442887] 主队列异步3   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.030223+0800 ModuleProject[17714:442887] 主队列异步3   <NSThread: 0x6000001c4d80>{number = 1, name = main}
2020-08-13 17:53:07.030405+0800 ModuleProject[17714:442887] 主队列异步3   <NSThread: 0x6000001c4d80>{number = 1, name = main}

2、GCD 线程间的通信

// 线程间通信
- (void)communication {
    // 全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 主队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        // 耗时操作放这里
        
        // 回到主线程
        dispatch_async(mainQueue, ^{
            // 追加在主线程中执行的任务
        });
    });
}

3、GCD 栅栏方法

当任务需要异步执行两组操作,第一组完成之后才能进行第二组的操作。这时候就用了到GCD的栅栏方法dispatch_barrier_async

// 栅栏方法 dispatch_barrier_async
- (void)barrierAsync {
    dispatch_queue_t queue = dispatch_queue_create("com.test", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_async(queue, ^{
        // 追加任务 2
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_barrier_async(queue, ^{
        // 追加任务 barrier
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"barrier---%@",[NSThread currentThread]);// 打印当前线程
    });
    
    dispatch_async(queue, ^{
        // 追加任务 3
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
}

打印结果
2020-08-12 17:01:20.653139+0800 ModuleProject[9201:308471] 2---<NSThread: 0x60000242c480>{number = 3, name = (null)}
2020-08-12 17:01:20.653132+0800 ModuleProject[9201:308467] 1---<NSThread: 0x60000242c4c0>{number = 4, name = (null)}
2020-08-12 17:01:22.656516+0800 ModuleProject[9201:308471] barrier---<NSThread: 0x60000242c480>{number = 3, name = (null)}
2020-08-12 17:01:24.660381+0800 ModuleProject[9201:308471] 3---<NSThread: 0x60000242c480>{number = 3, name = (null)}

4、GCD 队列组

当需要分别异步执行多个耗时任务,然后当多个耗时任务都执行完毕后再回到主线程执行任务。这时候我们可以用到 GCD 的队列组

  • dispatch_group_notify
    通过队列组的 dispatch_group_async 先把任务放到队列中,然后将队列放入队列组中;监听 group 中任务的完成状态,当所有的任务都执行完成后,追加任务到 group 中,并执行任务
// 队列组 dispatch_group_notify
 - (void)groupNotify {
    dispatch_group_t group =  dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 追加任务 2
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 等前面的异步任务 1、任务 2 都执行完毕后,回到主线程执行下边任务
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    NSLog(@"4---%@",[NSThread currentThread]);      // 打印当前线程
}
 
打印结果
2020-08-12 20:57:08.991816+0800 ModuleProject[1570:43381] 4---<NSThread: 0x60000015cdc0>{number = 1, name = main}
2020-08-12 20:57:10.995200+0800 ModuleProject[1570:43489] 1---<NSThread: 0x60000017f540>{number = 6, name = (null)}
2020-08-12 20:57:10.995198+0800 ModuleProject[1570:43488] 2---<NSThread: 0x600000113600>{number = 4, name = (null)}
2020-08-12 20:57:12.996592+0800 ModuleProject[1570:43381] 3---<NSThread: 0x60000015cdc0>{number = 1, name = main}
  • dispatch_group_wait
    dispatch_group_notify类似功能但是它阻塞当线程 ,等待指定的 group 中的任务执行完成后,才会往下继续执行。
/**
 * 队列组 dispatch_group_wait
 */
- (void)groupWait {
    dispatch_group_t group =  dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 追加任务 2
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    // 等待上面的任务全部完成后,会往下继续执行(会阻塞当前线程)
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    NSLog(@"4---%@",[NSThread currentThread]);      // 打印当前线程

}

打印结果
2020-08-12 21:00:30.398928+0800 ModuleProject[1618:46148] 1---<NSThread: 0x6000022f4e40>{number = 3, name = (null)}
2020-08-12 21:00:30.398934+0800 ModuleProject[1618:46144] 2---<NSThread: 0x6000022f1c00>{number = 6, name = (null)}
2020-08-12 21:00:30.399253+0800 ModuleProject[1618:46065] 4---<NSThread: 0x6000022b8240>{number = 1, name = main}
  • dispatch_group_enter、dispatch_group_leave
    什么时候会用到这个方法?
    在dispatch_group_async()里使用dispatch_async()方法,dispatch_group_notify不是在最后执行的。
- (void)groupEnterAndLeave {
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        for (NSInteger i =0; i<3; i++) {
            sleep(1);
            NSLog(@"任务1-异步任务执行-:%ld,thread:%@",(long)i,[NSThread currentThread]);
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        for (NSInteger i =0; i<3; i++) {
            sleep(1);
            NSLog(@"任务2-异步任务执行-:%ld,thread:%@",(long)i,[NSThread currentThread]);
        }
        dispatch_group_leave(group);
    });
    //等待上面的任务全部完成后,会收到通知执行block中的代码 (不会阻塞线程)
    dispatch_group_notify(group, queue, ^{
        NSLog(@"全部任务执行完成,thread:%@",[NSThread currentThread]);
    });
}

打印结果
2020-08-12 21:13:23.637769+0800 ModuleProject[1815:57379] 任务2-异步任务执行-:0,thread:<NSThread: 0x600002129b00>{number = 3, name = (null)}
2020-08-12 21:13:23.637756+0800 ModuleProject[1815:57377] 任务1-异步任务执行-:0,thread:<NSThread: 0x60000215ecc0>{number = 4, name = (null)}
2020-08-12 21:13:24.639234+0800 ModuleProject[1815:57377] 任务1-异步任务执行-:1,thread:<NSThread: 0x60000215ecc0>{number = 4, name = (null)}
2020-08-12 21:13:24.639234+0800 ModuleProject[1815:57379] 任务2-异步任务执行-:1,thread:<NSThread: 0x600002129b00>{number = 3, name = (null)}
2020-08-12 21:13:25.643570+0800 ModuleProject[1815:57377] 任务1-异步任务执行-:2,thread:<NSThread: 0x60000215ecc0>{number = 4, name = (null)}
2020-08-12 21:13:25.643625+0800 ModuleProject[1815:57379] 任务2-异步任务执行-:2,thread:<NSThread: 0x600002129b00>{number = 3, name = (null)}
2020-08-12 21:13:25.643995+0800 ModuleProject[1815:57379] 全部任务执行完成,thread:<NSThread: 0x600002129b00>{number = 3, name = (null)}

5、信号量

dispatch_semaphore_create可以生成信号量,参数value是信号量计数的初始值;dispatch_semaphore_wait会让信号量值减一,当信号量值为0时会等待(直到超时),否则正常执行
dispatch_semaphore_signal会让信号量值加一,如果有通过dispatch_semaphore_wait函数等待Dispatch Semaphore的计数值增加的线程,会由系统唤醒最先等待的线程执行

  • 异步操作转换为同步
 - (void)semaphoreSync {
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 1、semaphore 初始创建时计数为 0。
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    __block int number = 0;
    dispatch_async(queue, ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
        
        number = 100;
        // 3、执行 dispatch_semaphore_signal 之后,总信号量加 1,此时 semaphore == 0,正在被阻塞的线程(主线程)恢复继续执行。
        dispatch_semaphore_signal(semaphore);
    });
    // 2、执行 dispatch_semaphore_wait 方法,semaphore 减 1,此时 semaphore == -1,当前线程进入等待状态。
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
	// 4、最后打印 semaphore---end,number = 100。
    NSLog(@"semaphore---end,number = %zd",number);
}
  • 为线程加锁

// 线程安全:使用 semaphore 加锁
- (void)initTicketStatusSave {
    _semaphoreLock = dispatch_semaphore_create(1);
    
    self.ticketSurplusCount = 10;
    
    // queue1 代表北京火车票售卖窗口
    dispatch_queue_t queue1 = dispatch_queue_create("net.bujige.testQueue1", DISPATCH_QUEUE_SERIAL);
    // queue2 代表上海火车票售卖窗口
    dispatch_queue_t queue2 = dispatch_queue_create("net.bujige.testQueue2", DISPATCH_QUEUE_SERIAL);
    
    __weak typeof(self) weakSelf = self;
    dispatch_async(queue1, ^{
        [weakSelf saleTicketSafe];
    });
    
    dispatch_async(queue2, ^{
        [weakSelf saleTicketSafe];
    });
}

/**
 * 售卖火车票(线程安全)
 */
- (void)saleTicketSafe {
    while (1) {
        // -1 相当于加锁
        dispatch_semaphore_wait(_semaphoreLock, DISPATCH_TIME_FOREVER);
        
        if (self.ticketSurplusCount > 0) {  // 如果还有票,继续售卖
            self.ticketSurplusCount--;
            NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]);
            [NSThread sleepForTimeInterval:0.2];
        } else { // 如果已卖完,关闭售票窗口
            NSLog(@"所有火车票均已售完");
            
            // 相当于解锁
            dispatch_semaphore_signal(_semaphoreLock);
            break;
        }
        
        // 相当于解锁
        dispatch_semaphore_signal(_semaphoreLock);
    }
}

打印结果
2020-08-12 21:50:36.752994+0800 ModuleProject[2266:81059] 剩余票数:9 窗口:<NSThread: 0x600002ebf940>{number = 4, name = (null)}
2020-08-12 21:50:36.957438+0800 ModuleProject[2266:81057] 剩余票数:8 窗口:<NSThread: 0x600002ed4700>{number = 5, name = (null)}
2020-08-12 21:50:37.162657+0800 ModuleProject[2266:81059] 剩余票数:7 窗口:<NSThread: 0x600002ebf940>{number = 4, name = (null)}
2020-08-12 21:50:37.367371+0800 ModuleProject[2266:81057] 剩余票数:6 窗口:<NSThread: 0x600002ed4700>{number = 5, name = (null)}
2020-08-12 21:50:37.571037+0800 ModuleProject[2266:81059] 剩余票数:5 窗口:<NSThread: 0x600002ebf940>{number = 4, name = (null)}
2020-08-12 21:50:37.774617+0800 ModuleProject[2266:81057] 剩余票数:4 窗口:<NSThread: 0x600002ed4700>{number = 5, name = (null)}
2020-08-12 21:50:37.975415+0800 ModuleProject[2266:81059] 剩余票数:3 窗口:<NSThread: 0x600002ebf940>{number = 4, name = (null)}
2020-08-12 21:50:38.179218+0800 ModuleProject[2266:81057] 剩余票数:2 窗口:<NSThread: 0x600002ed4700>{number = 5, name = (null)}
2020-08-12 21:50:38.383655+0800 ModuleProject[2266:81059] 剩余票数:1 窗口:<NSThread: 0x600002ebf940>{number = 4, name = (null)}
2020-08-12 21:50:38.583949+0800 ModuleProject[2266:81057] 剩余票数:0 窗口:<NSThread: 0x600002ed4700>{number = 5, name = (null)}
2020-08-12 21:50:38.788986+0800 ModuleProject[2266:81059] 所有火车票均已售完
2020-08-12 21:50:38.789250+0800 ModuleProject[2266:81057] 所有火车票均已售完

本文地址:https://blog.csdn.net/qq_32644987/article/details/107955594