刚接触开发的童鞋,在学习多线程的时候,往往会比较吃力.因为这家伙比较抽象,有的时候较难通过运行代码直接看到多线程操作应该有的实际效果.和UI相比,多线程部分更注重理解. 所以,希望能通过这个故事,帮助大家更好地理解iOS中的多线程.故事是以GCD为主要实现手段进行展开的. OK,那废话不多说,一起走进财富故事汇之屎壳郎老板的公厕生意吧!

#屎壳郎老板和它的公厕生意 屎壳郎老板在旅游区开了一间收费公厕,招待南来北往的旅客们。来上厕所的客人,都是跟着各自的旅行团来的。屎壳郎老板要求上厕所的客人一定要排好队,一个一个来,讲文明,懂礼貌,谢绝插队和随地大小便等不文明行为。

#奇葩的旅客、奇葩的团 屎壳郎老板发现,来它这里上厕所的旅客,都非常怪异: 明明坑位很多,排队的人也很多,可是有的时候只有一个坑位被使用,有的时候同时有好多坑位被使用。
为了弄清楚坑位的使用规律,屎壳郎老板对来上厕所的旅客,和他们所在的旅行团进行了调查统计分析。


– 旅客篇 –

根据旅客的尿意程度,屎壳郎老板把旅客分为两类:

  • 尿急型
  • 有备无患型

尿急型旅客

  • 一旦前面的坑位没人,这类旅客就会一头扎进坑位中。

通过数据分析,屎壳郎老板还发现:

  • 尿急型旅客只认准靠窗的蹲位,别的蹲位一概不去。

###有备无患型旅客 这类旅客其实不是很急着上厕所,他们只是看到排队上厕所的人多,想通过排队等坑位的时间,来拓展自己的人脉圈的(如此高明的拓展人脉圈手段也是醉了-_-|||) 轮到他们进坑的时候,他们不会一头扎进去,而是

  • 先勾搭他后面的旅客

    “嘿哥们儿,一起啊~”

看到后面的哥们准备动身了,他才动身

屎壳郎老板还发现,这类旅客:

  • 一般会尽最大可能不用靠窗的坑位。

附注

由于尿急型旅客不主动招呼排在他后面的旅客,所以,后面的旅客只有亲眼看到尿急旅客已经方便完从坑位出来了,才会选坑进入。


– 旅行团篇 –

研究完旅客,屎壳郎老板又对旅客们所在的旅行团做了分析和归类。根据旅行团印发的《关于参团游客排队上公厕秩序的相关规定》内容进行划分(这旅行团管的也太宽了吧-_-|||),大致可以分为三大类

  • 宽松型
  • 严格型
  • 苛刻型

宽松型

团规:团内旅客尽量用最短的时间解决完上厕所问题,使用哪个坑位不做限制。

严格型

团规:不管有没有空余的坑位,本团内,一次只能有一个旅客在坑位上。

苛刻型

团规:本团内的旅客,只能使用靠窗的那个坑位。


屎壳郎老板很开心,因为有了这两份资料,他就能提前判断出,下一次,会有几个旅客同时进坑,以及他们分别会用几号坑位。


屎壳郎老板的测试题

OK,屎壳郎老板收集到的情报我们已经掌握了,那么,屎壳郎老板给大家出了一份测试题,我们一起来试着分析下吧!

题目:

假设这次排队的旅客有四个:
其中 三个来自名叫“严格旅行团”的严格型旅行团
另外两个来自名叫“宽松旅行团”的宽松型团

根据从前到后的顺序,他们分别是:
* 小A同学:来自宽松团,有备无患型
* 小B同学:来自宽松团,有备无患型
* 小C同学:来自严格团,尿急型
* 小D同学:来自宽松团,有备无患型
* 小E同学:来自严格团,尿急型 

模拟入坑过程

第一阶段

  1. 轮到排在最前面的小 A 同学入坑了,由于小 A是个有备无患型的,扭过头来招呼小 B:“嘿哥们儿~一起啊~”
  2. 小 B 同学也兴奋的扭过头招呼小 C:” 嘿哥们,一起啊~”
  3. 小 C 已经憋很久了,拔腿就准备往蹲位里冲。
  4. 小 B 看到小 C 准备动身了,自己也整理整理准备动身。
  5. 小 A 看小 B 准备动身了,自己马上动身走向坑位。因为是有备无患型,所以小 A 讨厌靠窗的1号蹲位,选择了2号蹲位。
  6. 小 B 动身前也思考了一下,我们团允许多个团员同时入坑。于是小 B 也动身了。有备无患型,讨厌靠窗的1号蹲位,2号蹲位又有人了,于是选择了3号蹲位
  7. 虽然便意浓浓,但小 C 还是略一思忖:我们团规定一次只能一个人入坑,前面入坑的两个都不是我们团的,看来我能入坑。然后看了一眼坑位:我喜欢的靠窗1号坑正好没人用!然后拔腿奔向了1号坑位。

总结:第一阶段同时入坑的有ABC三 位同学,分别使用了2号坑、3号坑和1号坑

第二阶段

  1. 亲眼看见小 C 从蹲位里面带幸福的走出来,小 D 知道,轮到自己了。于是招呼小 E 一起入坑
  2. 小 E 二话不说低着头就准备往坑里冲。小 D 见状略一思忖:我们团允许多个本团成员一起入坑,虽然之前两个团员小 A 和小 B 还没出来(假设小 A 和小B 解决的比较慢),但我还是可以入坑的。 于是动身选坑位
  3. 1号坑位虽然没人,但是小 D不喜欢,2号3号有人了(小 A 小 B 在里面),所以小 D 选择了4号坑位
  4. 小 E 临行前也简单思考了下:我们团没有人在蹲位中,1号蹲位没有人。于是小 E 冲向了1号蹲位。

总结:第二阶段同时入坑的有 DE 两位同学,分别使用了4号坑和1号坑。

验证

OK~分析完成,我们用代码来验证下是不是这样~

代码们

屎壳郎老板的测试题 - 代码验证.png

可以尝试自己运行下看看结果是不是和我们分析的一样哦!

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    //  创建名叫“严格旅行团”的严格型旅行团
    dispatch_queue_t seriouslyTeam = dispatch_queue_create("com.azen.xu", DISPATCH_QUEUE_SERIAL);
    //  创建名叫“宽松旅行团”的宽松型旅行团
    dispatch_queue_t relaxingTeam = dispatch_queue_create("com.azen.xu",DISPATCH_QUEUE_CONCURRENT);
    
    
    //  创建宽松团的有备无患型小 A
    dispatch_async( relaxingTeam, ^{
        //  让小 A 便便的时间长一点
        for (int i = 0 ; i <= 1000 ; i++)
        {
            NSLog(@"我是小 A,我在便便 -- 完成度 %%%.3f ---%@",i * 0.1,[NSThread currentThread]);
        }
    });
    //  创建与小 A 相似的小 B
    dispatch_async( relaxingTeam, ^{
        //  让小 B 便便的时间也长一点
        for (int i = 0 ; i <= 1000 ; i++)
        {
            NSLog(@"我是小 B,我在也便便 -- 完成度 %%%.3f ---%@",i * 0.1,[NSThread currentThread]);
        }
    });
    //  创建严格团的尿急小 C
    dispatch_sync(seriouslyTeam, ^{
        //  小 C 便的时间短一点
        for (int i = 0 ; i <= 10 ; i++)
        {
            NSLog(@"我是小 C,我在也便便 -- 完成度 %%%d ---%@",i * 10,[NSThread currentThread]);
        }
    });
    //  宽松团的有备无患型小 D
    dispatch_async( relaxingTeam, ^{
        //  让小 D 便便的时间也长一点
        for (int i = 0 ; i <= 1000 ; i++)
        {
            NSLog(@"我是小 D,我在也便便 -- 完成度 %%%.3f ---%@",i * 0.1,[NSThread currentThread]);
        }
    });
    //  严格团的尿急小 E
    dispatch_sync( seriouslyTeam, ^{
        //  让小 E 便便的时间也长一点
        for (int i = 0 ; i <= 1000 ; i++)
        {
            NSLog(@"我是小 E,我在也便便 -- 完成度 %%%.3f ---%@",i * 0.1,[NSThread currentThread]);
        }
    });
}

总结

嗯哼~ 故事讲完了。没看明白?不知道这鬼东西有什么卵用?不妨看看下面的对照表哦:

概念对照表

  1. 旅客 对应 任务 1.1 尿急型旅客 对应 同步任务 1.2 有备无患型旅客 对应 异步任务
  2. 旅行团 对应 队列 2.1 宽松型旅行团 对应 并发队列(Concurrent Dispatch Queue) 2.2 严格型旅行团 对应 串行队列(Serial Dispatch Queue) 2.3 苛刻型旅行团 对应 主队列(Main Queue)
  3. 蹲位 对应 线程 3.1 靠窗蹲位 对应 主线程 (所有涉及 UI 展示方面的任务都要在主线程中执行,所以… 主线程就是靠窗的蹲位啦…) 3.2 其他蹲位 对应 子线程

应用

尝试用多线程知识实现:分 六个任务别打印A、B、C、D、E 、F 六个字母,要求:A打印完后打印 B 和 C(要求BC几乎同时打印),C 打印完后打印D、E、F( DEF几乎同时打印)

最后的最后

一个故事并不能将多线程的知识完全讲清楚,只是希望,这篇小小的、有点怪诞、槽点满满的故事,能带给大家一点轻松快乐的好心情。会心一笑,然后带着这份好心情,一起继续在这个充满魔法的编程世界里前行吧~ ^_^

PS. 刚编出来这个故事时候,每次上厕所看到蹲位都忍不住想笑… 不过想到边排泄边傻笑可能有点怪怪的…所以还是忍住了= =

PPS. 屎壳郎老板的故事还没有结束哦!下一篇——《屎壳郎老板的神奇宝贝——蹲位兽》,和大家一起探秘屎壳郎老板公厕的蹲位,顺便聊一点runloop的小知识^_^