美文网首页
多线程网络01

多线程网络01

作者: 努力爬行中的蜗牛 | 来源:发表于2019-11-27 17:23 被阅读0次
    1 进程和线程

    1.1 进程
    进程是指在系统中正在运行的一个应用程序。
    比如同时代开迅雷、Xcode、系统就会分别启动两个进程。

    1.2 线程
    一个进程要想执行任务,必须得有线程(每一个进程至少要有1条线程)。
    一个进程的所有任务都在线程中执行。
    1个线程里面的任务是串行执行的。
    如果要在一个线程中执行多个任务,那么只能一个一个地按顺序执行这些任务。
    也就是说,在同一个时间内,1个线程只能执行一个任务。

    1.3 进程和线程的比较
    线程是CPU调用的最小单位。
    进程是CPU分配资源和调度的单位。
    一个程序可以对应多个进程,一个进程中可以有多个线程,但至少要有一个线程。
    同一个进程内的线程共享进程的资源。

    2 多线程

    2.1 多线程定义
    1个进程可以开启多条线程,每条线程可以并行执行不同的任务。进程->车间 线程->车间工人

    2.2 多线程原理
    同一时间,CPU只能处理1条线程,只有1条线程在工作(单CPU)。
    多线程并发执行,其实是CPU快速的在多个线程间调度(切换)。
    如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象。

    3 多线程在ios开发中的应用

    3.1
    一个iOS程序运行后,默认会开启1条线程,称为主线程或者UI线程

    3.2 主线程的主要作用
    显示、刷新UI界面
    处理UI事件(比如点击事件、滚动事件、拖动事件等)

    3.3 主线程的应用注意
    不要将比较耗时的操作放到主线程中
    耗时操作会卡主主线程,严重影响UI的流畅度。

    4 iOS开发中多线程的实现方案
    技术方案 简介 语言 线程生命周期 使用频率
    pthread 一套通用的多变成api,适用于Unix、linux、windows等系统,跨平台、可移植,使用难度大 c 程序管理 几乎不用
    NSThread 使用面向对象,简单易用,可以直接操作线程对象 OC 程序员管理 偶尔使用
    GCD 旨在替代NSThread等线程技术,充分利用设备的多核 C 自动管理 经常使用
    NSOperation 基于GCD(底层是GCD) OC 自动管理 经常使用
    5 NSThread的基本使用

    5.1 开启线程方法

    // 需要手动启动线程
    - (void)createNewThread1 {
        // 1. 创建线程
        /*
         第一个参数:目标对象 self
         第二个参数:方法选择器 调用的方法
         第三个参数: 前面调用方法需要传递的参数 nil
         */
        NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"ABC"];
        
        //2.启动线程
        [thread start];
    }
    
    // 分离子线程,自动启动线程
    - (void)createNewThread2 {
        [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"--分离子线程--"];
    }
    
    
    // 开启一条后台线程
    - (void)createNewThread3 {
        [self performSelectorInBackground:@selector(run:) withObject:@"开启后台线程"];
    }
    
    - (void)run:(NSString *)param {
        NSLog(@"---run----%@", [NSThread currentThread]);
    }
    
    6 线程的生命周期

    线程的生命周期:当线程中的任务执行完毕后被释放掉。

    7 线程的状态

    新建线程(New)(放入可调度线程池)->就绪(Runable)->运行(Running)


    001.png 002.png
    8 多线程的安全隐患

    8.1 资源共享问题
    1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源。
    比如多个线程访问同一个对象,同一个变量,同一个文件。
    当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题。

    8.2 安全隐患解决-互斥锁


    003.png
    9 原子和非原子属性
    004.png
    10 线程间通信

    10.1 线程间通信
    在一个进程中,线程间往往不是孤立的,多个线程之间需要经常及进行通信

    10.2 线程间通信的体现

    • 1个线程传递数据给另一个线程
    • 在一个线程中执行完特定任务后,转到另一个线程继续执行任务

    10.3 线程间通信常用方法

    [self performSelectorOnMainThread:(nonnull SEL) withObject:(nullable id) waitUntilDone:(BOOL)]
    [self performSelector:(nonnull SEL) onThread:(nonnull NSThread *) withObject:(nullable id) waitUntilDone:(BOOL)]
    
    Snip20191210_3.png Snip20191210_5.png
    11 GCD基本概念

    11.1 什么是GCD

    • 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器"
      纯C语言,提供了非常多强大额函数

    • GCD的优势
      GCD是苹果公司为多核的并行运算提供的解决方案
      GCD会自动利用更多的CPU内核
      GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
      程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

    11.2 任务和队列

    • GCD中有2个核心概念
      任务:执行什么操作
      队列:用来存放任务

    • GCD的使用就2个步骤
      定制任务:确定要做的事
      将任务添加到队列中
      GCD会自动将队列中的任务取出,放到对应的线程中执行
      任务的取出遵循队列的FIFO原则:先进先出,后进后出

    11.3 执行任务

    • GCD中有2个用来执行任务的常用函数
    • 用同步的方式执行任务
    dispatch_sync(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)
    
    • 用异步的方式执行任务
    dispatch_async(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)
    
    • 同步和异步的区别
      同步:只能在当前的线程中执行任务,不具备开启新线程的能力
      异步:可以在新的线程中执行任务,具备开启新线程的能力

    11.4 队列的类型

    • GCD的队列可以分为2中类型

    • 并发队列(Concurrent Dispatch Queue)
      可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
      并发功能只有在异步函数才有效

    • 串行队列(Serial Dispatch Queue)
      让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

    • 有4个术语比较容易混淆:同步、异步、并发、串行
      同步和异步的主要影响:能不能开启新的线程
      同步:只能在当前的线程中执行任务,不具备开启新线程的能力
      异步:可以在新的线程中执行任务,具备开启新线程的能力

    • 并发和串行主要影响:任务的执行方式
      并发:允许多个任务并发(同时执行)
      串行:一个任务执行完毕后,再执行下一个任务

    12 GCD的基本使用
    // 异步函数+并发队列:会开启多线线程,队列中的任务是并发执行的
    - (void)asyncConcurrent {
        // 1. 创建队列
        /*
         第一个参数:c语言字符串,标签
         第二个参数:队列类型
         */
        //dispatch_queue_t queue = dispatch_queue_create("com.520it.download", DISPATCH_QUEUE_CONCURRENT);
        // 获得全局并发队列
        /*
         第一个参数:优先级
         第二个参数:备用参数
         */
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        // 2. 1>封装任务2>添加任务到队列中
        dispatch_async(queue, ^{
            NSLog(@"download1--%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"download2--%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"download3--%@",[NSThread currentThread]);
        });
    }
    
    // 异步函数+串行队列:会开启1条线程,队列里面的任务是串行执行的
    - (void)asyncSerial {
        // 1. 创建队列
        /*
         第一个参数:c语言字符串,标签
         第二个参数:队列类型
         */
        dispatch_queue_t queue = dispatch_queue_create("com.520it.download", DISPATCH_QUEUE_SERIAL);
        // 2. 1>封装任务2>添加任务到队列中
        dispatch_async(queue, ^{
            NSLog(@"download1--%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"download2--%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"download3--%@",[NSThread currentThread]);
        });
    }
    
    // 同步函数+并发队里:不会开启线程,队列里面的任务是串行执行
    - (void)syncConcurrent {
        // 1. 创建队列
        /*
         第一个参数:c语言字符串,标签
         第二个参数:队列类型
         */
        dispatch_queue_t queue = dispatch_queue_create("com.520it.download", DISPATCH_QUEUE_CONCURRENT);
        // 2. 1>封装任务2>添加任务到队列中
        dispatch_sync(queue, ^{
            NSLog(@"download1--%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"download2--%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"download3--%@",[NSThread currentThread]);
        });
    }
    
    // 同步函数+串行队里:不会开启线程,队列里面的任务是串行执行
    - (void)syncSerial {
        // 1. 创建队列
        /*
         第一个参数:c语言字符串,标签
         第二个参数:队列类型
         */
        dispatch_queue_t queue = dispatch_queue_create("com.520it.download", DISPATCH_QUEUE_SERIAL);
        // 2. 1>封装任务2>添加任务到队列中
        dispatch_sync(queue, ^{
            NSLog(@"download1--%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"download2--%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"download3--%@",[NSThread currentThread]);
        });
    }
    
    13 主队列的相关用法

    13.1 串行队列
    GCD获得串行队列2中途径

    • 使用dispatch_queue_create函数创建串行队列
    • 使用主队列(跟主线程相关连的队列)
      主队列是GCD自带的一种特殊的串行队列
      放在主队列中的任务,都会放在主线程中执行
      使用dispatch_get_main_queue()获得主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    // 异步函数+主队列:不会开启新的线程,所有任务都在主线程中串行执行
    - (void)asyncMainQueue {
        // 获取主队列
        dispatch_queue_t queue = dispatch_get_main_queue();
        // 2. 1>封装任务2>添加任务到队列中
        dispatch_async(queue, ^{
            NSLog(@"download1--%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"download2--%@",[NSThread currentThread]);
        });
        
        dispatch_async(queue, ^{
            NSLog(@"download3--%@",[NSThread currentThread]);
        });
    }
    
    // 同步函数+主队列:死锁
    - (void)syncMainQueue {
        // 获取主队列
        dispatch_queue_t queue = dispatch_get_main_queue();
        // 2. 1>封装任务2>添加任务到队列中
        dispatch_sync(queue, ^{
            NSLog(@"download1--%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"download2--%@",[NSThread currentThread]);
        });
        
        dispatch_sync(queue, ^{
            NSLog(@"download3--%@",[NSThread currentThread]);
        });
    }
    

    注:主队列里面的任务,会放到主线程里面执行,当主线程有任务在执行的时候,主队列会等待主线程里面的任务执行完毕后,再执行主队列里面的任务

    14 同步和异步函数的区别和总结

    14.1 各种队列的执行效果

    队列 并发队列 手动创建的串行队列 主队列
    同步(sync) 没有开启新线程,串行执行任务 没有开启新线程,串行执行任务 死锁
    异步(async) 有开启新线程,并发执行任务 有开启新线程,任务串行执行 没有开启新线程,串行执行任务
    15 线程间通信
    // 创建子线程
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSURL *url = [NSURL URLWithString:@"http://hiphotos.baidu.com/bailiyu/pic/item/898e36836ca0dd9b6d81190a.jpg"];
            
            NSData *data = [NSData dataWithContentsOfURL:url];
            // 更新UI
            dispatch_async(dispatch_get_main_queue(), ^{
                self.imageView.image = [UIImage imageWithData:data];
            });
        });
    
    16 GCD常用函数

    16.1 延迟执行

    // 延迟执行
    - (void)delay {
        // 方法1
        //[self performSelector:@selector(task) withObject:nil afterDelay:2];
        
        // 方法2
        //[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(task) userInfo:nil repeats:YES];
        
        // 方法3
        /*
         参数1:DISPATCH_TIME_NOW 从现在开始计算时间
         参数2:延迟时间  2.0 GCD单位时间:纳秒
         参数3:队列
         */
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@">>>:%@",[NSThread currentThread]);
        });
    }
    

    16.2 一次性代码

    - (void)once {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSLog(@"%@",[NSThread currentThread]);
        });
    }
    

    相关文章

      网友评论

          本文标题:多线程网络01

          本文链接:https://www.haomeiwen.com/subject/gkypwctx.html