美文网首页
IOS - 多线程 基础

IOS - 多线程 基础

作者: Th丶小伟 | 来源:发表于2020-12-18 16:41 被阅读0次

    什么是线程

    线程(英语:thread)是操作系统能够进行运算调度的最小单位。

    什么是进程

    进程(英语:process),是计算机中已运行程序的实体
    一个进程中可以并发多个线程,每条线程并行执行不同的任务。

    什么是程序

    程序(英语:procedure),指特定的一系列动作、行动或操作,而这些活动、动作或操作必须以相同方式运行,借此在相同环境下恒常得出相同的结果(例如紧急应变程序)

    他们的区分方法
    程序真正运行在计算机中的实体,就变成了进程,(正在运行的程序叫进程)而进程可以包含一个或多个线程。

    OC三种线程技术

    1.NSThread------每个NSThread对象对应一个线程,量级较轻(真正的多线程)
    优点:NSThread 比其他两个轻量级
    缺点:需要自己管理线程的生命周期、线程同步、睡眠以及唤醒。线程同步对数据的加锁会有一定的系统开销

    2.NSOperation------NSOperation/NSOperationQueue 面向对象的线程技术,基于GCD
    优点:不需要关心线程管理, 数据同步的事情,可以把精力放在自己需要执行的操作上
    添加操作之间的依赖关系,方便的控制执行顺序
    设定操作执行的优先级
    可以很方便的取消一个操作的执行
    使用 KVO 观察对操作执行状态的更改

    3.GCD------Grand Central Dispatch(派发) 是基于C语言的框架,可以充分利用多核,是苹果推荐使用的多线程技术
    优点: GCD主要与block结合使用。代码简洁高效。执行效率稍微高点。
    会自动管理线程的生命周期
    会自动利用更多的CPU内核

    GCD队列及执行方式

    串行队列:一个接一个的执行任务 dispatch_queue_create("pw_GCD", DISPATCH_QUEUE_SERIAL)
    并发队列:可以同时调度多个任务  dispatch_queue_create("pw_GCD", DISPATCH_QUEUE_CONCURRENT)
    全局队列:dispatch_get_global_queue(0, 0)
    
    同步 : 一个任务没有结束,就不会执行下一个任务
    异步 : 不用等待任务执行完毕,就会执行下一个任务 (会开启子线程 )
     
    串行队列,同步执行   不会开辟线程   会按顺序执行
    串行队列,异步执行   会开线程      会按顺序执行
    
    并发队列  同步执行   不会开线程    会按顺序执行
    并发队列  异步执行   会开线程      不会按顺序执行
    

    Operation队列及执行方式

    主队列:凡是添加到主队列中的操作,都会放到主线程中执行(注:不包括操作使用addExecutionBlock:添加的额外操作,额外操作可能在其他线程执行 )[NSOperationQueue mainQueue] 
    
    

    operation跟GCD的区别

    1. GCD是底层的C语言,operation是基于GCD封装
    2. operation可以随时取消已经设定要准备执行的任务,GCD需要很复杂的代码才能取消
    3. 能够将KVO应用在operation中,监听operation是否完成或取消,能比GCD更加有效的掌控后台线程
    4. operation能够设置优先级,在同一并行队列中任务区分先后执行。
    5. NSOperation的高级:最大并发数,控制线程个数,优化了线程的暂停、继续、取消功能

    线程安全

    线程锁

    1、互斥锁 NSLock :对于互斥锁,当一个线程获得这个锁之后,其他想要获得此锁的线程将会被阻塞,直到该锁被释放

    @synchronized(锁对象) { // 需要锁定的代码 } 适用线程不多,任务量不大的多线程加锁
    优缺点:

    2、条件锁:NSCondition [lock lockWhenCondition:1];

    优点:线程安全

    缺点:性能很低

    3、递归锁:NSRecursiveLock
    使用递归锁可以在一个线程中反复获取锁而不造成死锁,这个过程中会记录获取锁和释放锁的次数,只有最后两者平衡锁才被最终释放。

    使用格式
    @synchronized(锁对象) { // 需要锁定的代码 }

    优点:能有效防止因多线程抢夺资源造成的数据安全问题
    缺点:需要消耗大量的CPU资源

    4、自旋锁:OSSpinLock
    当一个线程获得锁之后,其他线程将会一直循环在哪里查看是否该锁被释放(此锁比较适用于锁的持有者保存时间较短的情况下)

    不能保证线程安全

    线程安全 - GCD 栅栏方法:dispatch_barrier_async

    我们有时需要异步执行两组操作,而且第一组操作执行完之后,才能开始执行第二组操作。这样我们就需要一个相当于 栅栏 一样的一个方法将两组异步执行的操作组给分割起来,当然这里的操作组里可以包含一个或多个任务。

        //前面的耗时操作执行完毕之后
        dispatch_barrier_async(queue, ^{
            // 追加任务 barrier
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"barrier---%@",[NSThread currentThread]);// 打印当前线程
        });
        // 栅栏方法 才会继续执行
    

    避免数据竞争
    注意:全局队列 禁用了栅栏函数

    线程安全 - GCD 信号量

    ====定义====:就是一种可用来控制访问资源的数量的标识,设定了一个信号量,在线程访问之前,加上信号量的处理,则可告知系统按照我们指定的信号量数量来执行多个线程

    GCD 中的信号量是指 Dispatch Semaphore,是持有计数的信号。类似于过高速路收费站的栏杆。可以通过时,打开栏杆,不可以通过时,关闭栏杆。在 Dispatch Semaphore 中,使用计数来完成这个功能,计数小于 0 时等待,不可通过。计数为 0 或大于 0 时,计数减 1 且不等待,可通过。

    ispatch_semaphore_create:创建一个 Semaphore 并初始化信号的总量
    dispatch_semaphore_signal:发送一个信号,让信号总量加 1
    dispatch_semaphore_wait:可以使总信号量减 1,信号总量小于 0 时就会一直等待(阻塞所在线程),否则就可以正常执行。
    
    dispatch_semaphore_create(1): 传入值必须 >=0, 若传入为 0 则阻塞线程并等待timeout,时间到后会执行其后的语句
    dispatch_semaphore_wait(signal, overTime):可以理解为 lock,会使得 signal 值 -1
    dispatch_semaphore_signal(signal):可以理解为 unlock,会使得 signal 值 +1
     
    

    注意:信号量的使用前提是:想清楚你需要处理哪个线程等待(阻塞),又要哪个线程继续执行,然后使用信号量。

    主要作用:

    • 保持线程同步,将异步执行任务转换为同步执行任务
    • 保证线程安全,为线程加锁

    定时器

    NSTimer定时器不够准确,会受runloop 模式的影响
    GCD里面的定时器不会受到runloop 模式影响,需要注意的是创建的定时器需要被强引用,不然在block回调之前就会被释放

    CADisplayLink 一个能让我们保证和屏幕刷新率同步的频率,将特定的内容画到屏幕上的定时器类
    比较常用的是前两个

    相关文章

      网友评论

          本文标题:IOS - 多线程 基础

          本文链接:https://www.haomeiwen.com/subject/dzqfnktx.html