iOS开发底层之多线程探索 - 19

Posted iOS_developer_zhong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS开发底层之多线程探索 - 19相关的知识,希望对你有一定的参考价值。


前言

本篇博客主要是探索下ios多线程。

提示:以下是本篇文章正文内容,下面案例可供参考

一、进程与线程?

1. 进程

  1. 进程是指在系统中正在运行的一个应用程序。
  2. 每个进程之间是独立的, 每个进程均运行在独立的内存空间

2. 线程

  1. 线程是进程的基本执行单元
  2. 程序启动会默认开启一跳线程,就是主线程。

3. 进程与线程的关系

  1. 一个进程的所有任务都在线程中执行。
  2. 进程想要执行任务,必须的有线程,进程至少有一条线程。
  3. 同一进程内的线程共享资源,但是进程之间的资源是独立的。
  4. 一个进程崩溃后,在保护模式下,并不会对其他的进程产生影响,但在一个线程出现崩溃, 这个进程也会崩溃。 健壮性多进程大于多线程。
  5. 进程切换,消耗的资源大,而线程不会,因为它共享了进程中的所有资源。
  6. 线程依赖于进程。
  7. 线程没有地址空间,线程包含在进程地址空间中。

二、多线程

1. 多线程优点

  1. 能提高程序的执行效率。
  2. 能提高资源的利用率
  3. 线程执行完毕后,会自动销毁。

2.多线程缺点

  1. 开启线程,占用一定的内存空间, 默认每条线程占用512KB 。
  2. 线程越多,CPU调动开销就越大。
  3. 程序设计会复杂,进程通讯,多线程的数据共享,资源竞争。

3.线程的生命周期

新建 -》 就绪 -》 运行 -》 阻塞 -》 就绪 -》运行
新建 -》 就绪 -》 运行 -》 死亡

4. 线程池的饱和策略 RejectedExecutionHandler接口

  1. 主动抛出异常 RejectedExecutionExeception
  2. CallerRunsPolicy 将任务回退到调用者
  3. DisOldestPolicy, 抛弃掉执行最久的任务
  4. DisCardPolicy , 直接丢弃任务。

5. 优先级翻转 (IO vc cpu优先级提升)

  1. IO密集型 频繁等待
  2. CPU 密集型 很少等待
  3. 饿死
  4. 调度。
    CPU会根据等待时间的加长,慢慢提升IO优先级。

6. 优先级的影响因素

  1. 用户指定
  2. 等待的频繁度
  3. 长时间没有执行,也会提高优先级

三. 多线程下的问题

1. 资源抢夺的解决方法

  1. 自旋锁 ((atomic标识符)底层为 spinlock)
    发现其他线程执行,询问 - 忙等, 耗费性能比较高
    使用场景: 短小,任务执行简单
atomic : 原子属性,为多线程开发准备,默认属性
         在属性的setter方法中,增加了锁(自旋锁),保证同一时间只有一跳线程进行写操作。 

nonatomic: 非原子属性, 没有锁,性能高。 
  1. 互斥锁 (@synchronized 、)
    发现其他线程执行 , 休眠, 一直在等打开,唤醒执行。
    使用场景: 其他复杂的场景。

四. GCD 简单介绍

1. GCD简介

GCD是苹果公司为多核的并行运算提出解决方案
作用: 将任务添加到队列,并且指定执行任务的函数。

任务使用Block封装: 没有参数没有返回值



// 异步执行
dispatch_async  
/*
1 不会阻塞线程
2 会开启线程执行block的任务
3 多线程一般都是异步执行
*/

// 同步执行
dispatch_sync
/*
1. 会阻塞线程,必须等待执行完毕,才能往下执行
2. 不会开启线程
3. 在当前线程执行block的任务。 
*/

2. 串行队列 与 并行队列 (数据结构 FIFO)

  1. 简单使用(异步,同步执行)
 // 最基础写法。 
    dispatch_block_t block = ^{
        NSLog(@"hello GCD");
    };
    //串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.lg.cn", NULL);
    // 函数
    dispatch_async(queue, block);

// 主线程异步执行
dispatch_async(dispatch_get_main_queue(), ^{
	NSLog(@"1");
});

// 全局并发队列异步执行
dispatch_async(dispatch_get_global_queue(0, 0), ^{
	NSLog(@"%d-%@",i,[NSThread currentThread]);
});

  1. 自定义串行队列
    //创建同步串行队列
    dispatch_queue_t queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
	dispatch_sync(queue, ^{
            NSLog(@"%d-%@",i,[NSThread currentThread]);
	});
	
    //创建异步串行队列
    dispatch_queue_t queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
	dispatch_async(queue, ^{
            NSLog(@"%d-%@",i,[NSThread currentThread]);
	});
	
  1. 自定义并行队列
    //创建同步并发队列
    dispatch_queue_t queue = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
	dispatch_sync(queue, ^{
            NSLog(@"%d-%@",i,[NSThread currentThread]);
	});
	
    //创建异步并发队列
    dispatch_queue_t queue = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
	dispatch_async(queue, ^{
            NSLog(@"%d-%@",i,[NSThread currentThread]);
	});
	
  1. 经典死锁情况
// 串行队列,异步执行里面执行同步操作。 
    dispatch_queue_t queue = dispatch_queue_create("cooci", NULL);
    NSLog(@"1");
    dispatch_async(queue, ^{
        NSLog(@"2");
        dispatch_sync(queue, ^{   // 串行队列, 这里同步函数会堵塞住线程, 原因: 线程的执行规则是FIFO, 所以这里一定会先执行2 , 但是 任务3,这里是同步函数,是立即执行, 所以会产生堵塞3,而根据执行顺序, 2需要先执行完。 造成了相互等待,所以就产生了死锁。 
            NSLog(@"3");
        });
        NSLog(@"4");
    });
    NSLog(@"5");

// 情况二: 主线程同步执行
	dispatch_queue_t queue = dispatch_get_main_queue();
	dispatch_sync(queue, ^{
       
        NSLog(@"---11--");
    });
    
    

总结

1. 任务的执行速度的影响因素

  1. cpu
  2. 任务的复杂度
  3. 优先级
  4. 线程状态

以上是关于iOS开发底层之多线程探索 - 19的主要内容,如果未能解决你的问题,请参考以下文章

iOS开发底层之多线程探索 - 19

iOS开发底层之多线程探索 - 19

iOS底层探索之多线程—初识GCD

iOS底层探索之多线程(十五)—@synchronized源码分析

iOS底层探索之多线程(十四)—关于@synchronized锁你了解多少?

iOS底层探索之多线程—GCD源码分析(栅栏函数)