iOS-GCD的理解与使用
一、任务和队列
任务:在线程中执行的操作;执行任务有两种方式:同步执行
和 异步执行
:
- 同步执行:同步添加任务到队列中,前一个任务没有执行完,后面不能执行。不开辟新线程
- 异步执行:异步添加任务到队列中,任务同一时间可以一起执行。开启多个新线程
队列:队列是一种特殊的线性表,采用 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
推荐阅读
-
java中join方法的理解与说明详解
-
Mybatis动态sql、if与where的使用、sql片段、foreach遍历、Mybatis的关联查询一对一、一对多、多对多、Mybatis的延时加载
-
Java中final关键字的使用与注意总结
-
Python的索引与切片原来该这样理解
-
使用jQuery实现验证上传图片的格式与大小_jquery
-
css @page的使用与定义详解
-
jquery.extend 与 jquery.fn.extend的区别和使用
-
php 深入理解strtotime函数的使用详解
-
vue公共事件总线eventBus的简单理解和使用
-
详解Python的Django框架中manage命令的使用与扩展