IMG_5822.JPG

定义

线程

  • 进程的基本执行单元,一个进程的所有任务都在线程中执行
  • 进程想要执行任务,必须得有线程,进程至少要有一条线程
  • 程序启动会默认开启一条线程,这条线程被称为主线程或UI线程
  • 能开辟的最大线程数跟CPU有关

    进程

  • 系统中正在运行的一个应用程序

  • 每个进程之前是独立的,每个进程均运行在其专用的且受保护的内存空间内
  • 通过“活动监视器”可以查看Mac系统中所有开启的进程

    说明

  • iOS是单进程,Android是多进程,可以进程间通讯,多任务是多线程。

  • 进程是有内存空间的,线程没有内存空间,共享使用本进程的空间,而进程之前则是独立的地址空间
    • TLS(Thread Local Storage),线程局部存储(例:同步锁时,存储syncData),是某些操作系统为线程单独提供的私有空间,但通常只具有很有限的容量。
  • iOS中有pthread、NSThread、NSOperation、GCD

    原理

  • Cpu单位时间片内切换调度任务

    状态

  • 新建线程,调用start后,线程进入就绪状态(runnable),此时cpu可调度,当cpu调度当前线程,状态为运行(running),当前线程有两种状态

    • 调用sleep、等待同步锁、从可调度线程池移除,进入阻塞状态(Blocked)
    • 直接挂掉(Dead)

    未命名文件 (3).jpg
    未命名文件 (37).jpg

  • 可调度线程池

    • 线程池存在阈值(任何任务都是依赖于线程执行)
      1. 核心线程是否正在运行,是否都有任务,创建新的工作线程去执行
      2. 线程池工作队列是否饱和->将任务存储在工作队列
      3. 线程池中的线程都处于执行状态->安排线程去执行
      4. 交给饱和策略去处理(这四种拒绝策略均实现了RejectedExecutionHandler接口)
        1. 直接抛出异常RejectExecutionExeception异常来阻止系统正常运行
        2. 将任务回退到调用者
        3. 丢掉等待最久的任务
        4. 直接丢掉任务

未命名文件 (5).jpg

  • 任务的执行速度的影响因素
    • cpu调度
    • 任务复杂度
    • 线程状态
    • 优先级

未命名文件 (22).jpg

  • 优先级反转
    • IO密集型 -> 频繁等待,IO相对于cpu优先级提升
    • CPU密集型 -> 很少等待
    • 饿死,OSSpinLock
    • 调度,任务的优先级不断提升,造成优先级反转
  • 优先级因素

    • 用户指定
    • 根据等待的频繁度
    • 长时间不执行也会提升优先级

  • 自旋锁,发现其它线程执行当前线程,询问+忙等,耗费性能比较高。

    • 短小任务使用,比如atomic。

      • atomic是原子属性,是为多线程开发准备的,是默认属性
      • 仅仅在属性的Setter方法中,增加了锁(自旋锁),能够保证同一时间,只有一条线程对属性进行‘写’操作,同一时间 单线程写多线程读的线程处理技术
      • atomic在底层源码中只是一个标识符判断,判断是否添加自旋锁,底层是spinLock
      • noatomic,没有锁,性能高 ```cpp static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) { ….

      if (!atomic) { oldValue = slot; slot = newValue; } else { spinlock_t& slotlock = PropertyLocks[slot]; slotlock.lock(); oldValue = slot; slot = newValue;
      slotlock.unlock(); }

      objc_release(oldValue); } ```

  • 互斥锁,发现其它线程执行当前线程,休眠(就绪状态)一直在等打开,唤醒执行。

    GCD

  • 将任务添加到队列,并指定执行任务的函数

  • 以下任务block并未执行block(),添加到了队列后,指定了函数执行 ```cpp
  • (void)syncTest { ///<< 创建任务 dispatch_block_t block = ^{

    1. NSLog(@"hello, GCD");

    }; ///<< 添加到队列 dispatch_queue_t queue = dispatch_queue_create(“com.cc.cn”, NULL); ///<< 指定函数执行 dispatch_async(queue, block); } ```

    队列

  • 队列,是一种数据结构,FIFO

    • 串行队列,任务1一定在任务2前,一个个执行
    • 并发队列,具备任务调度能力,但不具备执行能力,执行依赖线程池中的线程
    • image.png
  • 无论同步函数还是异步函数,都是耗时任务 ```cpp // 同步队列 dispatch_queue_t queue = dispatch_queue_create(“cooci”, DISPATCH_QUEUE_CONCURRENT); NSLog(@”1”); // 异步函数 dispatch_async(queue, ^{
    1. NSLog(@"2");
    2. // 同步
    3. dispatch_sync(queue, ^{
    4. NSLog(@"3");
    5. });
    6. NSLog(@"4");
    }); NSLog(@”5”);

运行结果 1 -> 5 -> 2 -> 3 -> 4

  1. - **以下会出现死锁,打印 1 -> 5 -> 2,无论去掉12行与否,都会死锁,任务块在后面添加新任务**
  2. - **_dispatch_sync_f_slow**
  3. ```cpp
  4. // 同步队列
  5. dispatch_queue_t queue = dispatch_queue_create("cooci", NULL);
  6. NSLog(@"1");
  7. // 异步函数
  8. dispatch_async(queue, ^{
  9. NSLog(@"2");
  10. // 同步函数:护犊子,堵塞11行以后的代码执行
  11. dispatch_sync(queue, ^{
  12. NSLog(@"3");
  13. });
  14. // 无论去掉以下代码都会死锁
  15. NSLog(@"4");
  16. });
  17. NSLog(@"5");

未命名文件 (24).jpg

补充

  • 以下函数可能打印结果:
  • 任务依次加入到主队列中,加到NSLog(0)后,但是任务3护犊子,所以先执行
  • queue为并发队列时
    • 任务3是同步函数,会阻塞其后面的执行,所以任务3在任务4前执行
    • 任务4一定在任务5、6、7前执行
    • 任务1、2、3顺序不固定
    • 任务7、8、9顺序不固定
    • 答案是A、C
  • queue为串行队列时
    • 自上而下依次执行dispatch_async -> dispatch_async -> dispatch_sync -> …
    • 任务NSLog被加入到串行队列中,所以打印顺序为1230789
    • 答案是A
  1. dispatch_queue_t queue = dispatch_queue_create("com.lg.cooci.cn", DISPATCH_QUEUE_CONCURRENT);
  2. ///<< 任务1
  3. dispatch_async(queue, ^{
  4. NSLog(@"1");
  5. });
  6. ///<< 任务2
  7. dispatch_async(queue, ^{
  8. NSLog(@"2");
  9. });
  10. ///<< 任务3
  11. dispatch_sync(queue, ^{ NSLog(@"3"); });
  12. ///<< 任务4
  13. NSLog(@"0");
  14. ///<< 任务5
  15. dispatch_async(queue, ^{
  16. NSLog(@"7");
  17. });
  18. ///<< 任务6
  19. dispatch_async(queue, ^{
  20. NSLog(@"8");
  21. });
  22. ///<< 任务7
  23. dispatch_async(queue, ^{
  24. NSLog(@"9");
  25. });
  26. // A: 1230789
  27. // B: 1237890
  28. // C: 3120798
  29. // D: 2137890

未命名文件 (2).jpg