多线程

主要涉及解决线程间同步及资源共享方面的解决方案。

iOS系统为我们提供的多线程技术方案有哪些?
GCD(使用频度最高),NSOperation(图片异步下载),NSThread(常驻线程)









NSThread




文字简述:(1)当创建好一个线程并开启线程(CPU或许在调度其他的线程,所以也许不会马上调度新开启的这个线程,因为CPU是来回切换执行的),那么就会把这个线程对象放进图中绿色的可调度线程池里面进入就绪状态等待CPU调度,(2)假设过了一会CPU(CPU是切换执行的,会分配给这个线程一个时间片)有时间了切换到这个线程上调度,那么这个线程就进入运行状态,如果这期间CPU在分配的时间片里没有把这个线程执行完毕又停下这个线程的执行去调度其他的线程,那么会记录此时这个线程执行的状态再切换到其他线程,此刻这个线程状态重新变为就绪状态(3)如果这个线程调用sleep方法/等待同步锁,那么这个线程就进入阻塞状态,sleep到时/得到同步锁,才会重新进入就绪状态(4)线程的死亡有自然死亡和非自然死亡,自然死亡就是线程执行完毕,非自然死亡就是发生异常或者程序强制退出了




起了线程名字,如若该线程出现异常,可以快速定位到问题。




线程执行的时间不由我们确定,每次的执行都不确定,像刚刚上面这种情况线程是不安全的,不能保证数据和预期的结果是一致的。
下面是解决方案:用互斥锁来防止因多线程抢夺资源造成的数据安全问题





注意⚠️:如果[多线程]访问同一个资源,那么必须使用同一把锁才能锁住,在开发中,尽量不要加锁,能在服务端做尽量在服务端做,如果必须要加锁,一定要记住,锁的范围不能太大,哪里有[安全隐患]就加在哪里。
技巧:因为必须使用同一把锁,开发中如果需要加锁,直接使用 self 即可。
线程间通讯
子线程创建任务,在主线程更新UI

GCD

Test1

test1

答案1

Test1文字简述:
viewDidLoad和Block都是在主线程调用,那么两者都被加入主队列(主队列本身就是串行队列)中,(重点是队列相互等待,而不是线程问题,不管是不是主队列 是要是同一个队列 都会发生死锁)由于主队列先进先出FIFO的特性,执行完viewDidLoad才能执行block,可是block是同步在ViewDidLoad方法里,所以就造成了互相等待的死锁问题。

Test2

Test2

答案二

test2文字简述:
重点在于是加在了不同的队列。block是加在一个自定义队列,而不是与viewDidLoad同一个队列,所以先执行viewDidLoad,执行到block的时候,因为是同步的方式 所以会先把serialQueue上的任务dosomething执行完,就会继续往下执行,所以是没有问题的,不存在相互等待的问题

Test3

Test3

Test3答案简述:输出:1,2,3,4,5,这是对同步并发队列的理解
global_queue为全局并发队列,里面的任务为并发执行。
按代码顺序输出1,(同步方式提交任务到并发队列还是串行队列,它都是在当前线程完成)同步方式提交一个任务到全局并发队列中,那么打印2在主线程中执行,同步方式提交一个任务到全局并发队列中,那么打印3在主线程中执行,然后打印4,打印5

Test4

Test4

文字简述:

  • performSelector:withObject:afterDelay:其实就是在内部创建了一个NSTimer,然后会添加到当前线程的Runloop中
  • 因为方法里有延迟执行,所以内部有NSTimer计时,timer只有在runloop开启的状态下才能执行,而这个block块是异步方式,子线程的runloop默认情况下是关闭状态,所以不会调用printLog
    那么怎样才可以打印1,2,3呢?把子线程的runloop打开不就好了吗?是的 在log3上面,performSelector下面这个位置加上
    [[NSRunLoop currentRunLoop] run];
    那么疑问又来了 是不是在block块里哪个位置都可以比如log1下面?答案是不行的 下面截出run的一段官方文档如下:
Discussion

If no input sources or timers are attached to the run loop, this method exits immediately; otherwise, it runs the receiver in the `NSDefault<wbr>Run<wbr>Loop<wbr>Mode`by repeatedly invoking [runMode:beforeDate:](apple-reference-documentation://hcGlc34FMW). In other words, this method effectively begins an infinite loop that processes data from the run loop’s input sources and timers. 

Manually removing all known input sources and timers from the run loop is not a guarantee that the run loop will exit. macOS can install and remove additional input sources as needed to process requests targeted at the receiver’s thread. Those sources could therefore prevent the run loop from exiting.

意思就是如果当前runloop没有任何事件(source、timer、observer)的话,那么它会马上退出,所以应该写在selector下面,这样就可以保证开启runloop的时候 有事件timer,那么runloop就不会退出了

Test5 多读单写

多读单写test5

多读单写方案:

dispatch_barrier_async(dispatch_queue_create("concurrent_queue", DISPATCH_QUEUE_CONCURRENT), ^{
       //写操作
    });
test4

为什么要同步读取呢?因为获得数据是想可以很快得到的,实现多读就是objectforkey可以在多个线程调用,所以多个线程传入并发队列,也就实现了多读。

Test6: dispatch_group_async

Test6
 dispatch_queue_t concurrent_queue = dispatch_queue_create("concurrent_queue", DISPATCH_QUEUE_CONCURRENT);
//创建一个队列组
    dispatch_group_t group = dispatch_group_create();
    for (int i = 0; i < 3; i ++) {
        //异步组分派到并发队列当中
        //在队列组group中的concurrent_queue队列中添加任务
        dispatch_group_async(group, concurrent_queue, ^{
           //下载
        });
    }
    //会执行dispatch_group_notify这个方法,但是里面的block块只会当队列中的人物全部执行完毕才会执行
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
       //当添加到组中的所有任务执行完成之后会调用该block
    });

Test7

NSOperation

1.NSOperation任务执行状态有:

  • isReady. 当前任务是否就绪
  • isExcecuting 是否处于正在执行中
  • isFinish 是否已完成
  • isCancel led 是否已取消

2.状态控制:

  • 如果只重写了main方法,底层控制变更任务执行完成状态,以及任务退出
  • 如果重写了start方法,自行控制任务状态

只重写main源码分析:首先看start方法:首先是创建一个自动释放池,然后获取线程的优先级,然后进行一系列状态异常判断,如果没有异常,会判断是否处于正在执行中,如果是没有执行,则设置为正在执行的状态,之后会在判断当前任务是否被取消,如果没有被取消,就会调用NSOperation 的 main函数,之后调用finish,之后调用自动释放池的release操作。


Test8 NSThead

Test8

test:NSThead启动流程的内部实现:首先创建一个NSThead之后会调用start方法,然后来启动线程,在start方法内部会创建一个pThead线程,然后会指定pThead中的一个启动函数,在启动函数中会调用pThead所定义的main函数, 之后在main函数中会通过target performSelector来执行目标函数selector,最后调用exit来结束这个线程
test: 如果要实现一个常驻线程的话,可以在selector方法里维护一个runloop,实现事件的运行循环,从而达到实现常驻线程的目的

Test8 锁

iOS当中有哪些锁?

  • @synchronized:一般在创建单例对象的时候使用,从而保证在多线程情况下创建对象是唯一的。
  • atomic:修饰属性的关键字;对被修饰对象进行原子操作(不负责使用,就是只对赋值setter保证线程安全 但是对于可变数组的使用add delete不保证线程安全的)
  • OSSpinLock自旋锁:循环等待访问,不释放当前资源(比如去房间有人会一直敲门),用于轻量级数据访问,简单的int值 +1/-1操作
  • NSLock解决线程同步问题 来保证各个线程互斥进入自己的临界区
  • NSRecursiveLock 递归锁
  • dispatch_semaphore_t


    test8_1

    简述:锁已经使用过了,所以需要等到锁解开才可以再次访问加锁,线程被阻塞住了,这就造成了死锁。


    解决8_1

    简述:在这种情况下,我们就可以使用NSRecursiveLock。它可以允许同一线程多次加锁,而不会造成死锁。递归锁会跟踪它被lock的次数。每次成功的lock都必须平衡调用unlock操作。只有所有达到这种平衡,锁最后才能被释放,以供其它线程使用。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容