GCD
简述
串行队列: 顺序, 一个一个执行. 并发对列: 可以同时把很多任务取出来, 有线程就执行. 同步任务: 不会开辟新的线程, 在当前线程中执行. 异步会开辟新的线程 串行队列每次只会拿出一个任务执行, 因此串行异步任务最多只会创建两个线程(即子线程和主线程).
串行并行针对于队列而言, 同步异步针对于线程而言.
同步和异步决定了要不要开启新的线程
同步: 当前线程中执行, 不具备开启新线程的能力. 但会马上执行
异步: 在新的线程中执行, 具备开启线程的能力. 但不会立即执行
并发和串行决定了任务的执行方式
并发: 多个任务并发/同时执行
串行: 一个任务执行完, 再执行另外一个任务.
串行/并行描述的是处理任务的速度问题
同步/异步描述的是处理任务的先后顺序问题
主队列: dispatch_get_main_queue()
同步任务, 立刻执行
异步队列, 只是添加到主队列, 但不会立即执行.
在主队列中, 异步添加10人任务. 执行的顺序: 主队列先执行-然后才是添加到主队列的10个任务再执行.
在主队列中, 同步添加10个任务. 执行的顺序: 会卡死. 因为同步队列立刻执行. 但这个时候主队列的任务正在执行. 主队列执行完之后才会执行同步任务, 因此等待同步任务执行完毕; 同步任务立刻执行, 同步任务执行完毕之后才会执行主队列. 双方都等待资源的释放, 因此卡死.
全局队列的本质就是并发队列, 但他是系统的.
全局队列和并发队列的区别: 调度任务的方式相同
- 全局队列没有名称, 并发队列有名称.
- 全局队列可以供所有的应用程序共享
队列的选择:
串行队列异步执行: 开一条线程, 顺序执行, 效率不高,占用资源少. 并发任务异步执行: 效率高, 占用资源大.
线程间通信: 在子线程中下载图片, 然后强制在主线程中更新图片.
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSURL *url = [NSURLURLWithString:@"https://ss2.baidu.com/-vo3dSag_xI4khGko9WTAnF6hhy/super/whfpf%3D425%2C260%2C50/sign=a4b3d7085dee3d6d2293d48b252b5910/0e2442a7d933c89524cd5cd4d51373f0830200ea.jpg"];
NSData *data = [NSDatadataWithContentsOfURL:url];
UIImage *image = [UIImageimageWithData:data];
// 在主线程跟新UI
dispatch_async(dispatch_get_main_queue(), ^{
self.imageview.image = image;
});
});
线程调度组, 线程依赖
// 实际开发中,有时候在多个网路请求完成以后,需要统一的通知用户
dispatch_group_t group =dispatch_group_create();
dispatch_queue_t queue =dispatch_get_global_queue(0,0);
dispatch_group_async(group, queue, ^{
NSLog(@"1111111111111111111111111111111111111111");
});
dispatch_group_async(group, queue, ^{
NSLog(@"22222222222222222222222222222222222222222222");
});
dispatch_group_async(group, queue, ^{
NSLog(@"33333333333333333333333333333333333333333333");
});
dispatch_group_notify(group,dispatch_get_main_queue(), ^{
NSLog(@"========通知我执行完了===========");
});
* 好几个任务执行完之后, 统一做一件事
// group表示要等待的组,DISPATCH_TIME_NOW表示等待的时间.返回值表示要等待的时间: 0这个组已经执行完, 非0未执行完
dispatch_group_wait(group, DISPATCH_TIME_NOW);// 立即检查
dispatch_group_wait(group,DISPATCH_TIME_FOREVER);// 一直等到这个组的任务执行完, 此模式会阻塞
dispatch_suspend(queue);// 线程挂起和恢复 dispatch_resume(queue);
GCD延时方法
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
});
GCD只执行一次的方法
dispatch_once_t onceTocken;
dispatch_once(&onceTocken, ^{
NSLog(@"===%ld", onceTocken);
});
dispatch_sync(dispatch_get_main_queue(), ^{// 在主线程中执行这个方法会死锁 NSLog(@"xxx"); });
防止数据竞争 : 使用 dispatch_barrier_async 方法
dispatch_async(queue, block1_for_reading)
dispatch_async(queue, block2_for_reading)
dispatch_barrier_async(queue, block_for_writing)
dispatch_async(queue, block3_for_reading)
dispatch_async(queue, block4_for_reading)信号量
死锁问题
NSLog(@"1");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
队列中 有任务1在执行,这时候添加任务2到队列中. 主队列中的任务串行执行(任务1执行完之后,任务2才能执行,但任务2不执行完,任务1完成不了。任务1完成不了,任务2没法开始)
信号量
dispatch_semaphore_create(2) // 创建信号量
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER) // 加锁
dispatch_semaphore_signal(semaphore) // 解锁
工作中线程组和信号量的使用的应用
-
- 使用AFNetwork异步请求好几个任务全部结束之后, 统一做一件事
dispatch_group_t group =dispatch_group_create(); dispatch_group_enter(group); //---------使用AFNetwork请求数据------------- dispatch_group_leave(group); dispatch_group_enter(group); //---------使用AFNetwork请求数据------------- dispatch_group_leave(group); dispatch_group_enter(group); //---------使用AFNetwork请求数据------------- dispatch_group_leave(group); dispatch_group_notify(group,dispatch_get_main_queue(), ^{ // ... });
-
信号量
dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{ dispatch_semaphore_t sem = dispatch_semaphore_create(0); NSDictionary *dict = @{@"username" : @"23716997892", @"password" : @"123123", @"type" : @"1"}; [HTRequestHelper LoginDataParams:dict success:^(id responseObj) { NSLog(@"1111111111111111"); dispatch_semaphore_signal(sem); } failure:^(NSError *error) { dispatch_semaphore_signal(sem); }]; dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); }); dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{ dispatch_semaphore_t sem = dispatch_semaphore_create(0); [HTRequestHelper RefreshDataSuccess:^(id responseObj) { NSLog(@"2222222222222"); dispatch_semaphore_signal(sem); } failure:^(NSError *error) { dispatch_semaphore_signal(sem); }]; dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"3333333333333"); });