iOS晋级知识汇总(十)多线程

多线程

  • GCD
  • NSOperation(AFnetwork可以查看)
  • NSThread
  • 多线程与锁

GCD的相关问题

  • 同步/异步和串行/并发
  • dispatch_barrier_async
  • dispatch_group

同步?异步?串行?并发

  • dispatch_sync(serial_queue,^{});
  • dispatch_async(serial_queue,^{});
  • dispatch_sync(concurrent_queue,^{});
  • dispatch_async(concurrent_queue,^{});

在主线程中开启一个GCD同步任务

  • 队列引起的循环等待,造成的死锁
    • 在主线程中开启了一个同步任务,而这个同步任务,需要你前面的任务完成,而主线程在iOS中是一个特殊的线程,它会一直存在于你的程序结束之前。

首先ViewDidLoad执行处理,在执行过程中,他需要调用block,当block同步调用完成之后,这个ViewDidload才能继续向下走,ViewDidload方法处理结束,需要block调用完成以后。block任务要想执行,主队列是一个先进先出的性质,所以它要等到ViewDidLoad执行完成以后才能调用block的任务。这就造成了循环等待。

简单来讲就是,同步任务就是要等待队列中的上个任务完成以后才能调用这个同步任务。而这个同步任务,在上个任务之中。这就造成互相等待。

在主线程中开启一个GCD异步任务

在ViewDidLoad当中,在主线程中开启一个GCD异步任务。ViewDidLoad这个任务跟GCD异步任务并没有依赖关系,所以不会出现死锁

多线程的面试真题

-(void)GCDTest1{
    //全局并发队列
    dispatch_queue_t q = dispatch_get_global_queue(0, 0);
    //当前线程第一个打印日志1
    NSLog(@"1");
    //同步任务到全局队列中,所以dispatch_sync里面的代码会在主线程中执行。
    dispatch_sync(q, ^{
         //第二个打印日志2
        NSLog(@"2");
        //同步任务,会执行
        dispatch_sync(q, ^{
              //第三个打印日志3
            NSLog(@"3");
        });
        //第四个 打印日志4
        NSLog(@"4");
    });
    //第五个打印日志5
    NSLog(@"5");
}

异步串行

dispatch_async(dispatch_get_main_queue(), ^{
    
    NSLog(@"经常用到的主线程操作");
    
});

异步并发

-(void)GCDTest3{
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"1");
        //这个方法不会运行,因为runloop在子线程中默认是不开启的,所以用这句话不会执行
        [self performSelector:@selector(printlog) withObject:nil afterDelay:0];
        NSLog(@"3");
    });
    
}

打印结果是1、3。

如何运用dispatch_barrier_async(栅栏函数)

对一个磁盘DB进行读写,如何设计多读单写?

  • 读者、读者并发
  • 读者、写者互斥
  • 写者、写者互斥

用一个dispatch_barrier_async栅栏放入到并发队列来处理写操作。

- (id)GG_objectForkey:(NSString *)key{
    
    __block id obj;
    //并发任务就是可以多个执行
    dispatch_sync(concurrent_queue, ^{
        obj = [self->userCenterDic objectForKey:key];
    });
    //同步操作能立刻返回结果
    return obj;
}


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

调度组dispatch_group_async

使用GCD实现这个需求:A、B、C是那个任务并发,完成后执行任务D?

- (void)handle{
    
    dispatch_group_t group = dispatch_group_create();
    for (NSURL *url in arrayURLs) {
        
        dispatch_group_async(group, concurrent_queue, ^{
            NSLog(@"url is %@",url);
        });
        

    }
    dispatch_group_notify(group, concurrent_queue, ^{
       //当调度组中的任务全部完成以后才会调用这个函数
    });
    
}

NSOperation

需要和NSOperationQueue配合使用来实现多线程方案

优势:

  • 添加移除任务依赖,这些特点NSthread不具备,GCD不好实现的
- (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op;
  • 任务执行状态控制
  • 最大并发量

任务执行状态控制

  • isReady 当前任务是否处于就绪状态
  • isExecuting 当前任务是否是正在执行状态
  • isFinished 当前任务是否完成
  • isCancelled 当前任务是否已取消

状态控制

  • 如果只重写了main方法,系统的底层实现会控制变更任务执行完成状态,以及任务退出
  • 如果重写了start方法,自行控制任务状态,在合适的时机更新状态
    • 重写了start方法就是相当于,将系统控制状态的代码覆盖了。

NSOperation的源码

gnustep-base

系统是如何移除一个isFinished=YES的NSOperation的?

NSOperationQueue通过KVO来移除NSOperation的。

NSthread

启动流程

start -》创建pthread -〉 main -》 (RunLoop事件的运行循环)[target performselect:selector]->exit

NSthread创建流程.png

如果需要写一个常驻的线程需要我们在Select方法里面实现常驻runloop。

经常使用的锁

  • @synchchronized

  • atomic

  • OSSpinLock

  • NSRecursiveLock

  • NSLock

  • dispatch_semaphore_t

  • @synchchronized

    • 在创建单例对象的时候使用,来保证在多线程环境下,创建的对象是唯一的。
  • atomic

    • 修饰属性的关键字
    • 对被修饰对象进行原子操作(不负责使用)
      • 只负责赋值,不负责对象使用
  • OSSpinLock

    • 自旋锁,循环等待询问,不是放当前资源
    • 现在已经不安全了,优先级反转
    • 现在推荐使用,pthread的mutex
    • 专门用于轻量级数据访问,简单的int值 +1/-1操作
    • 从系统的runtime去学习,工作中很少用
  • NSLock

    • 加锁
    • 逻辑
    • 解锁
  • NSRecursiveLock

    • 递归锁,可以重入
    • 加锁和解锁是成对出现的。
  • dispatch_semaphore_t

    • 信号量,记录型信号量
    • create操作
      • struct semaphore
        • int value
        • list <thread>
    • wait -1 2个参数 信号量是哪个 等待时长
      • 内部操作是, value - 1
      • 当value小于0的时候 阻塞是一个主动行为
    • signal +1
      • value +1
      • value 仍然《=0 说明在释放信号之前还有线程还在排队,然后就会去把相应的线程唤醒,这样就可以实现一个线程同步,唤醒是一个被动的行为。由释放信号的线程来唤醒被阻塞的线程

多线程面试问题总结

怎么用GCD实现多读单写?

dispatch_barrier_async的使用

iOS系统为我们提供了几种多线程技术各自的特点

NSthread

实现常驻线程。

GCD

实现一些简单的线程同步,子线程的分派,多读单写

NSOperation和NSOperationQueue

第三方框架 afn sdweb
任务状态控制
添加依赖

NSOperation 对象在Finished之后是怎么样从Queue中当移除掉的

  • 通过KVO实现的,去通知Queue去移除 NSOperation

你都用过哪些锁?结合实际谈谈你是怎样使用的?

  • NSLock
  • NSRecursiveLock
  • dispatch_smphore_t
  • synchchronized
  • atomic
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • CPU不同调度:一个进程可以开启多条线程,每条线程可以并行执行不同的任务。任务执行完毕依赖于线程池:不一定按照固定...
    StevenHu_Sir阅读 236评论 0 1
  • NSThread 第一种:通过NSThread的对象方法 NSThread *thread = [[NSThrea...
    攻城狮GG阅读 795评论 0 3
  • 我只是一个搬运工,仅仅为了加深记忆,感谢作者分享,文章大部分来源:尚大大o_O 线程和进程 几乎所有的操作系统都支...
    zhu哥哥阅读 97评论 0 1
  • 一、知识结构分析 多线程之间的关系 pthread是POSIX线程的API NSThread是Cocoa对pthr...
    huoshe2019阅读 473评论 0 4
  • 之前看了很多面试题,感觉要不是不够就是过于冗余,于是我将网上的一些面试题进行了删减和重排,现在分享给大家。(题...
    Job_Yang阅读 12,103评论 12 143