zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

iOS 多线程 GCD(日常开发中使用频度最多的多线程技术方案)

ios多线程技术开发 方案 日常 gcd 最多
2023-09-14 09:04:14 时间

返回上级目录:iOS面试专题一

0.我的另外一篇博客

iOS 多线程 再学习

1.简介

请添加图片描述
请添加图片描述

2.同步串行

请添加图片描述

2.1 死锁

  • 队列引起的循环等待,而不是线程引起的循环等待
  • viewDidLoad执行过程中需要调用Block, Block完成后viewDidLoad方法才能继续向下走;viewDidLoad方法的结束需要依赖于后面提交的Block任务。Block任务要想执行需要等到viewDidLoad执行完成。循环等待
    请添加图片描述
    请添加图片描述
  • 同步提交,意味着在当前线程执行
    请添加图片描述

3.同步并发

  • 今日头条
  • global_queue: 并发队列,并发队列中的任务可以并发执行
  • global_queue改为串行队列会发生死锁
    请添加图片描述

4.异步串行

请添加图片描述

5.异步并发

  • 腾讯视频面试真题
  • GCD底层的线程默认是没有开启runloop的
  • performSelector方法会提交到当前线程的runloop
    请添加图片描述
  • 我自己的测试
    请添加图片描述

PerformSelector 和多线程的关系_sinat_32283541的博客-CSDN博客

iOS performSelector 实现原理 - 云+社区 - 腾讯云

6.dispatch_barrier_async():多读单写

苹果官方文档:dispatch_barrier_async

这个博客示例了dispatch_barrier_async:
dispatch_barrier_async 与 dispatch_barrier_sync区别

6.1 什么是多读单写

  • 滴滴公司和美团公司的面试题
    请添加图片描述
  • 栅栏异步调用
    请添加图片描述

6.2 代码实现

请添加图片描述

//
//  UserCenter.m
//  GCD
//
//  Created by yangyang38 on 2018/3/16.
//  Copyright © 2018年 yangyang. All rights reserved.
//

#import "UserCenter.h"

@interface UserCenter()
{
    // 定义一个并发队列
    dispatch_queue_t concurrent_queue;
    
    // 用户数据中心, 可能多个线程需要数据访问
    NSMutableDictionary *userCenterDic;
}

@end

// 多读单写模型
@implementation UserCenter

- (id)init
{
    self = [super init];
    if (self) {
        // 通过宏定义 DISPATCH_QUEUE_CONCURRENT 创建一个并发队列
        concurrent_queue = dispatch_queue_create("read_write_queue", DISPATCH_QUEUE_CONCURRENT);
        // 创建数据容器
        userCenterDic = [NSMutableDictionary dictionary];
    }
    
    return self;
}

- (id)objectForKey:(NSString *)key
{
    __block id obj;
    // 同步读取指定数据 同步方式可以立刻返回数据  并发队列多个读取操作可以并发执行
    //获取操作是要有立刻同步返回结果的,所以用_sync。 同步到并发队列中,就可以有多个线程同时读
    dispatch_sync(concurrent_queue, ^{
        obj = [userCenterDic objectForKey:key];
    });
    
    return obj;
}

- (void)setObject:(id)obj forKey:(NSString *)key
{
    // 异步栅栏调用设置数据
    dispatch_barrier_async(concurrent_queue, ^{
        [userCenterDic setObject:obj forKey:key];
    });
}

@end

6.3 我自己的测试示例

请添加图片描述

7.dispatch_group_async()

  • A,B,C中不开启新线程,结论才成立。A,B,C中代码都从头到尾执行完后会执行D。如果A中又开启新线程去下载图片(不会阻塞A的线程),那么当图片下载完回来,D可能已经执行完了.这是本人在项目中遇到要上传完多张图片后再执行任务,本来想用dispatch_group_async,结果发现不行,因为在下载图片是会异步开启新线程
  • 爱奇艺真题
    请添加图片描述

7.2 代码实现

//
//  GroupObject.m
//  GCD
//
//  Created by yangyang38 on 2018/3/16.
//  Copyright © 2018年 yangyang. All rights reserved.
//

#import "GroupObject.h"

@interface GroupObject()
{
    dispatch_queue_t concurrent_queue;
    NSMutableArray <NSURL *> *arrayURLs;
}

@end

@implementation GroupObject

- (id)init
{
    self = [super init];
    if (self) {
        // 创建并发队列
        concurrent_queue = dispatch_queue_create("concurrent_queue", DISPATCH_QUEUE_CONCURRENT);
        arrayURLs = [NSMutableArray array];
    }

    return self;
}

- (void)handle
{
    // 创建一个group
    dispatch_group_t group = dispatch_group_create();
    
    // for循环遍历各个元素执行操作
    for (NSURL *url in arrayURLs) {
        
        // 异步组分派到并发队列当中
        dispatch_group_async(group, concurrent_queue, ^{
            
            //根据url去下载图片
            
            NSLog(@"url is %@", url);
        });
    }
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 当添加到组中的所有任务执行完成之后会调用该Block
        NSLog(@"所有图片已全部下载完成");
    });
}
@end

7.3 我自己的测试例子

请添加图片描述

  • d2会在d1后执行,在target后执行
    请添加图片描述

8.gcd也有挂起和取消:queue.suspend() dispatchWorkItem.cancel()

  • 默认创建的是串行队列
    请添加图片描述

请添加图片描述
请添加图片描述