iOS-开辟子线程(NSThread、NSOperationQueue、GCD)

2023-05-16

本节主要总结一些开辟子线程的常用的几种方法。

一、通过NSThread类开辟子线程

1.NSThread手动开启子线程

// 创建线程对象.
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(eat) object:nil];
thread.name = @"a";

// 手动开启线程
[thread start];
// 手动取消线程
[thread cancel]

2.NSThread自动开启子线程

    // 创建线程对象自动开启,无返回值
    [NSThread detachNewThreadSelector:@selector(eat) toTarget:self withObject:nil];

除了创建启动外,NSThread 还以很多方法,更多方法可以去NSThread.h类的定义里去看,写的很详细。

3.子线程中执行完之后,回到主线程:

[self performSelectorOnMainThread:@selector(mainQueue) withObject:nil waitUntilDone:NO];

二、通过NSOperationQueue类开辟子线程

1.Queue (队列)中是 NSOperation 对象

一个 NSOperation 对象就是一个任务(一段功能代码),本身和线程没有关系(不能开子线程)。
NSOperation 只是一个抽象类,所以不能封装任务。但它有 2 个子类用于封装任务。分别是:NSInvocationOperation 和 NSBlockOperation 。创建一个 Operation 后,需要调用 start 方法来启动任务,它会默认在当前队列同步执行。当然你也可以在中途取消一个任务,只需要调用其 cancel 方法即可。这种方式任务都是在主线程中执行。

    // NSInvocationOperation 创建任务对象(多个)
    NSInvocationOperation *invocation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(eat) object:nil];
    NSInvocationOperation *invocation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(eat) object:nil];


    // NSBlockOperation 创建任务对象
    __weak typeof(self) weakSelf = self;
    //__weak ViewController *weakSelf = self;
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        [weakSelf eat]; // 任务1
    }];
    // addExecutionBlock会创建一个新的线程来执行任务,而不是在同一个子线程中。   
    [blockOperation addExecutionBlock:^{
        [weakSelf eat]; // 任务2
    }];
    [blockOperation addExecutionBlock:^{
        [weakSelf eat]; // 任务3
    }];

    // 开启线程
    [invocation1 start];
    [invocation2 start];
    [blockOperation1 start];

也可以直接添加进队列 NSOperationQueue 里面,任务会自动执行,不需要你再手动调用start方法。NSOperation 和 NSOperationQueue 类似于 GCD 的 任务队列这种方式任务都是在子线程中执行。

    // 创建 operationQueue 队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    //NSOperationQueue 有一个属性 maxConcurrentOperationCount 最大并发数,用来设置最多可以让多少个任务同时执行。当你把它设置为 1 的时候,变为串行队列!

    queue.maxConcurrentOperationCount = 1;

    [queue addOperation:invocation1];
    [queue addOperation:invocation2];

    [queue addOperation:blockOperation];

NSOperation 取消任务调用

    [invocation1 cancel];
    [blockOperation cancel];

2.子线程中执行完之后,回到主线程:

   [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        [weakSelf mainQueue];
    }];

NSOperation 还有好多属性方法,具体的可以NSOperation.h里面查看,会找到你需要的方法属性。

3.任务执行完成后回调

 [blockOperation setCompletionBlock:^{
     // 任务都执行完后回调
 }];

三、通过GCD开辟子线程

在 GCD 中,加入了两个非常重要的概念: 任务队列
任务:即操作,你想要干什么,说白了就是一段代码,在 GCD 中就是一个 Block,所以添加任务十分方便。任务有两种执行方式: 同步执行异步执行,他们之间的区别在于 是否会创建新的线程

1.GCD 核心: 队列和任务
2.队列: 串行队列和并行队列.
3.任务: block块 和 函数
4.程序本身有一个串行队列(主线程).
5.有4个并行队列(优先级区别).
6.自定义一个串行队列
7.自定义并行队列.

同步和异步区别:同步(sync) 和 异步(async) 的主要区别在于会不会阻塞当前线程,直到 Block 中的任务执行完毕! 如果是同步(sync) 操作,它会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行。 如果是异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程。

队列:用于存放任务。一共有两种队列, 串行队列 和 并行队列。

串行队列: 放到串行队列的任务,GCD 会 FIFO(先进先出) 地取出来一个,执行一个,然后取下一个,这样一个一个的执行。

并行队列: 放到并行队列的任务,GCD 也会 FIFO的取出来,但不同的是,它取出来一个就会放到别的线程,然后再取出来一个又放到另一个的线程。这样由于取的动作很快,忽略不计,看起来,所有的任务都是一起执行的。不过需要注意,GCD 会根据系统资源控制并行的数量,所以如果任务很多,它并不会让所有任务同时执行。

任何需要刷新 UI 的工作都要在主队列执行,所以一般耗时的任务都要放到别的线程执行。

它自己可以创建 串行队列, 也可以创建 并行队列.它有两个参数,第一个参数是标识符,用于 DEBUG 的时候标识唯一的队列,可以为空。第二个才是最重要的。第二个参数用来表示创建的队列是串行的还是并行的,传入DISPATCH_QUEUE_SERIAL 或 NULL 表示创建串行队列。传入 DISPATCH_QUEUE_CONCURRENT 表示创建并行队列。

//***************** 自定义串行队列 *****************//
// 串行队列 SERIAL
dispatch_queue_t queue = dispatch_queue_create("SERIAL", DISPATCH_QUEUE_SERIAL);

    // 防止循环引用 使用 __weak 修饰
    __weak typeof(self)weakSelf = self;
    // 异步任务 分线程中执行 不会阻塞主线程
    dispatch_async(queue, ^{
        [weakSelf eat];
    });
   // 同步任务 主线程中执行 会阻塞当前线程
    dispatch_sync(queue, ^{        
        [weakSelf eat];
    });
    //***************** 自定义并行队列 *****************//
    // 并行队列 CONCURRENT
    dispatch_queue_t queue2 = dispatch_queue_create("CONCURRENT", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue2, ^{
        [weakSelf eat];
    });
    dispatch_sync(queue2, ^{
        [weakSelf eat];
    });
//***************** 获取系统的4个并行队列 ****************//
    dispatch_queue_t queue4 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue4, ^{
        [weakSelf eat];
    });

解决异步情况下抢占资源问题,可以加锁NSLock。获取资源时lock住,获取完资源后unlock。或者用@synchronized包裹获取资源代码。

1.子线程中执行完之后,回到主线程:

dispatch_async(dispatch_get_main_queue(), ^{
     // 更新UI
});

2.所有任务执行完成后回调

   dispatch_group_t group = dispatch_group_create();
   dispatch_group_async(group,queue2,^{执行任务A});
   dispatch_group_async(group,queue2,^{执行任务B});
   dispatch_group_async(group,queue2,^{执行任务C});
   dispatch_group_notify(group, dispatch_get_main_queue(), ^{
       NSLog(@"queue2的所有任务都执行完了");
   });

借鉴博客:
http://www.jianshu.com/p/0b0d9b1f1f19
http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
http://guimingsu.com/blog/2015/12/22/thread/

总结

1.无论使用哪种方法进行多线程开发,每个线程启动后并不一定立即执行相应的操作,具体什么时候由系统调度,CPU空闲时就会执行。

2.NSBlockOperation 添加任务 addExecutionBlock 任务全部完成时回调方法 setCompletionBlock;GCD任务全部完成时回调方法 dispatch_group_notify。

3.NSThread适合轻量级多线程开发,要手动控制线程,线程总数无法控制,无法线程依赖。

4.对于简单的多线程开发建议使用NSObject的扩展方法完成,而不必使用NSThread。

5.可以使用NSThread的currentThread方法取得当前线程,使用 sleepForTimeInterval:方法让当前线程休眠。

6.NSOperation进行多线程开发可以控制线程总数及线程依赖关系。

7.创建一个NSOperation不应该直接调用start方法, 如果直接start则会在主线程中调用, 而是应该放到NSOperationQueue中启动。

8.相比NSInvocationOperation推荐使用NSBlockOperation,代码简单,同时由于闭包性使它没有传参问题。

9.NSOperation是对GCD面向对象的封装,但是GCD基于C语言开发,效率却更高. 建议如果任务之间有依赖关系或者想要监听任务完成状态的情况下优先选择NSOperation否则使用GCD。

10.在GCD中串行队列中的任务被安排到一个单一的子线程中,可以方便地控制执行顺序;并发队列在多个线程中执行(前提是使用异步方法),顺序控制相对复杂,但是更高效。

11.在GDC中一个操作是多线程执行还是单线程执行取决于当前队列类型和执行方法,只有队列类型为并发队列并且使用异步方法执行时才能在多个线程中并发执行。

12.相比使用NSLock,@synchronized更加简单。

13.主队列是个串行队列,但是它不会新建子线程,所以当在主队列中执行dispatch_sync 时会卡死。

Demo下载地址https://github.com/MichaelSSY/ThreadTest

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS-开辟子线程(NSThread、NSOperationQueue、GCD) 的相关文章

随机推荐

  • 如何在Ubtun上安装vscode,保姆级教程

    Ubtun安装vscode 打开vm虚拟机安装VM tools 主要目的 xff1a 实现win上的文件与vm虚拟机上的文件进行共享 具体过程 参照B站 Ubuntu安装vmware tools和open vm tools Ubuntu安装
  • python matplotlib生成图表基础

    本节的目标是绘制一个y 61 x 2的函数图像 plot图表 绘制图表 plot xff08 xff09 函数绘制图表 xff0c 传入参数 xff0c 输入值和输出值 xff0c 还可以指定其他参数 plt span class toke
  • Cannot make a static reference to the non-static method XXX() from the type XXX

    不能用调用静态方法的方式调用一个非静态的方法 xff1a 我在定义方法的时候不是static的 出现这个报错是因为java调用任何方法都要实例化 xff0c c 43 43 里有函数的概念 xff0c 但是java里的函数实际上是类的方法
  • 【2022_10_17】PX4学习

    commander cpp内 int Commander custom command int argc char argv 221行 该函数接受所有commander输入的参数 xff0c strcmp比较后调用不同的函数 strcmp返
  • how to solveE:Unmet dependencies.Try‘apt --fix ^^^^^

    span class token function sudo span span class token function apt span span class token function install span span class
  • PX4报错FAILED: external/Stamp/sitl_gazebo/sitl_gazebo-configure解决

    PX4仿真gazebo报错 make px4 sitl default gazebo Configuring incomplete errors occurred span class token operator span See als
  • 汉诺塔问题的解法

    问题描述 相传在古印度圣庙中 xff0c 有一种被称为汉诺塔 Hanoi 的游戏 该游戏是在一块铜板装置上 xff0c 有三根杆 编号A B C xff0c 在A杆自下而上 由大到小按顺序放置64个金盘 如下图 游戏的目标 xff1a 把A
  • 51单片机——串口通信(发送和接受数据)

    目录 一 实现的功能 二 串口通信 2 1单片机发送数据 2 1 1串口初始化 2 1 2串口发送程序 2 1 3发送效果 2 2单片机接收数据 2 2 1串口初始化 2 2 2接收数据程序 2 2 3接收效果 一 实现的功能 通过串口 x
  • 无人机仿真SLAM_gazebo&promethues

    无人机仿真 总体概述系统要求 PX4固件简介无人机固件整体框图无人机软件框图无人机硬件模型 Mavlink模块位置估计与姿态估计模块安装与编译二次开发 机载计算机程序控制模块估计模块仿真模块SLAM模块SLAM效果演示 总体概述 无人机仿真
  • 编译orbslam2时,Pangolin could not be found because dependency Eigen3 could not be found,解决方法

    是因为使用了pangolin0 6版本 xff0c 需要重新安装0 5版本的pangolin 1 在pangolin的build文件夹下 sudo make uninstall 2 usr local include 删除pangolin文
  • CMakeLists.txt常用语法

    0 绪 cmake 是一个跨平台 开源的构建系统 它是一个集软件构建 测试 打包于一身的软件 它使用与平台和编译器独立的配置文件来对软件编译过程进行控制 1 常用命令 1 1制定cmake最小版本 cmake minimum require
  • Vue 模板

    原文 在Vue中 xff0c Vue模板对应的就是Vue中的View xff08 视图 xff09 部分 xff0c 也是Vue重中之一 xff0c 而在Vue中要了解Vue模板我们就需要从两个方面来着手 xff0c 其一是Vue的模板语法
  • Ubuntu:系统分区

    在系统分区之前 先进行磁盘分区 这里针对的是window10系统下安装ubuntu双系统 需要在window10下进行磁盘分区来安装ubuntu系统 一 磁盘分区 win10系统下 右击此电脑 xff0c 点击管理就进入磁盘管理 这时候可以
  • Mac 安装node.js

    Mac系统安装Node js xff0c 下载地址 如上图安装路径 xff1a This package will install Node js v16 19 1 to usr local bin node span class toke
  • MySQL 常用函数(二)

    ABS函数 xff1a 求绝对值 绝对值函数 ABS x 返回 x 的绝对值 正数的绝对值是其本身 xff0c 负数的绝对值为其相反数 xff0c 0 的绝对值是 0 span class token keyword SELECT span
  • MyBatis Mapper常用动态SQL之foreach 、if、choose、where、when

    if语句 lt if gt 判断语句 xff0c 用于单条件分支条件判断 使用 lt if gt 元素对参数username和jobs进行非空判断 xff0c 并动态组装SQL xff1a span class token keyword
  • Java 查看官方Java API文档

    话不多说 xff0c 直接上方法 打开官网址 xff1a http www oracle com technetwork cn java javase downloads index html 方式一 在线浏览 点击Java 文档 xff1
  • iOS-微信分享成功回调问题

    本人用ShareSDK做分享和第三方登录 xff0c 登录先不讲 xff0c 本节只做分享成功或失败后回调问题 相信好多人会有这个疑惑就是在微信分享成功后没有成功后的方法回调 xff0c 我在ShareSDK论坛也发表过帖子问过 xff0c
  • iOS-常见三种加密(MD5、非对称加密,对称加密)

    任何应用的开发中安全都是重中之重 xff0c 在信息交互异常活跃的现在 xff0c 信息加密技术显得尤为重要 在app应用开发中 xff0c 我们需要对应用中的多项数据进行加密处理 xff0c 从而来保证应用上线后的安全性 xff0c 给用
  • iOS-开辟子线程(NSThread、NSOperationQueue、GCD)

    本节主要总结一些开辟子线程的常用的几种方法 一 通过NSThread类开辟子线程 1 NSThread手动开启子线程 span class hljs comment 创建线程对象 span span class hljs built in