• ios线程总结(持续更新ing)


    一、什么是线程:

    1、1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程)

    2、线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行

    3、1个线程中任务的执行是串行的,如果要在1各线程中执行多个任务,那么只能一个一个地按顺序执行这些任务,也就是说,在同一时间内,1个线程只能执行1个任务

    二、什么是多线程

    1、1个进程中可以开启多条线程,每条线程可以并行(同时)执行不同的任务  

    例:进程 ——>车间  ,线程——>车间工人

    2、多线程的原理:同时间,CPU只能处理1条线程,只有1条线程在工作(执行),多线程并发(同时)执行,其实质是CPU快速地在多条线程之间调度(切换),当CPU调度线程的速度足够块,就造成了多线程并发执行的假象

    三、什么是主线程

    1、一个iOS程序运行后,默认会开启1条线程,成为“主线程”或“UI线程”

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

    3、使用主线程需要注意:别将比较耗时的操作放到主线程,会卡UI(阻塞UI)

    四、iOS中多线程的实现方案

    1、pthread

        简介:一套通用的线程API,适用于UnixLinuxWindows等系统;跨平台,可移植;使用难度大。

        语言:C

        线程生命周期:程序员管理

        使用频率:几乎不用

    示例代码: 

    2、NSThread

         简介:使用更加面向对象,简单易用,可直接操作线程对象

         语言:OC

         线程生命周期:程序员管理

         使用频率:偶尔使用

    创建线程实例代码:

    创建方式一:

    创建方式二:

    创建方式三(隐式创建并启动):

    线程安全:

               1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源,很容易引发数据错乱和数据安全问题。

    线程安全代码实例(加互斥锁):

    互斥锁使用格式: @synchronized(self){ //需要锁定的代码}

    注意:锁定1份代码只能用1把锁,用多把锁是无效的,且加过多的锁会消耗大量的CPU资源降低程序效率

    线程间通讯:

    线程其他方法:

    3、GCD

         简介:旨在替代NSThread等线程技术,充分利用设备的多核

         简介:C

         线程生命周期:自动管理

         使用频率:经常使用

        3.1 什么是GCD:全称(Grand Central Dispatch,可译为"伟大的调度中心")

        3.2 GCD的优势:

               3.2.1 GCD是苹果公司为多核并行运算提出的解决方案;

               3.2.2 GCD会自动利用更多的CPU内核(比如双核,四核)

               3.2.3 GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)

        3.3 GCD中有2个核心概念

               3.3.1 任务:执行什么操作

               3.3.2 队列:用来存放任务

              

        3.4 GCD的使用就2个步骤:

               步骤一:定制任务(确定想做的事情)

               步骤二:将任务添加到队列中(CGD会自动将队列中的任务取出,放到对应的线程中执行),任务的取出遵循队列的FIFO原则,先进先出,后进后出

        3.5 GCD中有2个用来执行任务的函数

              3.5.1 用同步的方式执行任务(在当前线程执行,不开启新线程)

              dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

              queue:队列

              block:任务

              3.5.2 用异步的方式执行任务(会开启新线程)

              dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

             在这里需要注意一点:GCD的队列可分为2大类型

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

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

    注意:同步和异步主要影响能不能开启新的线程,同步在当前线程中执行,不具备开启新线程的能力;异步在新的线程中执行任务,具备开启新线程的能力。并发和串行主要影响任务的执行方式,并发是多个任务并发(同时)执行,串行是一个任务执行完毕后再执行下一个任务。

        3.6 队列类型:(全局并发队列,串行队列,主队列)

              全局并发队列:GCD默认已经提供了全局的并发队列,提供整个应用使用,不需要手动创建

                                  获取全局并发队列的函数:dispatch_get_global_queue

                                  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

                                  参数1:全局并发队列的优先级(影响该队列的调度次数)

                                             DISPATCH_QUEUE_PRIORITY_HIGH 2  高

                                             DISPATCH_QUEUE_PRIORITY_DEFAULT 0  默认
                                             DISPATCH_QUEUE_PRIORITY_LOW (-2)  低
                                             DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN  后台

                                  参数2:该参数暂时没有任何作用,传0

             串行队列:GCD中获得串行队列有2种途径

                           途径1:使用dispatch_queue_create函数创建串行队列
                                     dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

                                      参数1:队列名称;参数2:队列属性,一般用NULL即可

                                      注:非ARC,需要释放创建的队列  dispatch_release(queue);

                            途径2:使用主队列(跟主线程相关的队列),主队列是GCD自带的一种特殊的串行队列,放在主队列中的任务,都会放到主线程中执行。获取主队:dispatch_get_main_queue()

        3.7 GCD同步异步以及队列的组合方式:主要掌握以下第一种方式即可,其他的组合方式可以直接忽略

    /**  组合类型一:
     *  async -- 并发队列(最常用)
     *  会不会创建线程:会,一般同时开多条
     *  任务的执行方式:并发执行
     */

    - (void)asyncGlobalQueue
    {
        // 获得全局的并发队列
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        // 将 任务 添加 全局队列 中去 异步 执行
        dispatch_async(queue, ^{
            NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
        });
         dispatch_async(queue, ^{
            NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
        });

        dispatch_async(queue, ^{
            NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
        });

        dispatch_async(queue, ^{
            NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
        });

    }

    /** 组合类型二:
     *  async -- 串行队列(有时候用)
     *  会不会创建线程:会,一般只开1条线程
     *  任务的执行方式:串行执行(一个任务执行完毕后再执行下一个任务)
     */
    - (void)asyncSerialQueue
    {
        // 1.创建一个串行队列,手动的,队列名称为heyifu.queue
        dispatch_queue_t queue = dispatch_queue_create("heyifu.queue", NULL);
        
        // 2.将任务添加到串行队列中 异步 执行
        dispatch_async(queue, ^{
            NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"-----下载图片2---%@", [NSThread currentThread]);
        });

        dispatch_async(queue, ^{
            NSLog(@"-----下载图片3---%@", [NSThread currentThread]);
        });

        dispatch_async(queue, ^{
            NSLog(@"-----下载图片4---%@", [NSThread currentThread]);
        });

        dispatch_async(queue, ^{
            NSLog(@"-----下载图片5---%@", [NSThread currentThread]);
        });

        
        // 3.非ARC,需要释放创建的队列
    //    dispatch_release(queue);
    }

    /**组合类型三:不会用到,这种方式组合是多余的,这样的效果与直接把任务放到主线程中调用是一样的
     *  sync -- 并发队列
     *  会不会创建线程:不会
     *  任务的执行方式:串行执行(一个任务执行完毕后再执行下一个任务)
     *  并发队列失去了并发的功能
     */
    - (void)syncGlobalQueue
    {
        // 获得全局的并发队列
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        // 将 任务 添加到 全局并发队列 中 同步 执行
        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
        });

        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片2---%@", [NSThread currentThread]);
        });

        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片3---%@", [NSThread currentThread]);
        });

        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片4---%@", [NSThread currentThread]);
        });

        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片5---%@", [NSThread currentThread]);
        });


    }

    /**组合类型四:不会用到,这种方式组合是多余的,这样的效果与直接把任务放到主线程中调用是一样的
     *  sync -- 串行队列
     *  会不会创建线程:不会
     *  任务的执行方式:串行执行(一个任务执行完毕后再执行下一个任务)
     */
    - (void)syncSerialQueue
    {
        // 创建一个串行队列
        dispatch_queue_t queue = dispatch_queue_create("heyifu.queue", NULL);
        
        // 将 任务 添加到 串行队列 中 同步 执行
        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片2---%@", [NSThread currentThread]);
        });

        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片3---%@", [NSThread currentThread]);
        });

        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片4---%@", [NSThread currentThread]);
        });

        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片5---%@", [NSThread currentThread]);
        });

    }

    /**组合类型五:
     *  async -- 主队列(很常用)不会开启新线程,一般用在线程间的通讯
     */
    - (void)asyncMainQueue
    {
        // 1.主队列(添加到主队列中的任务,都会自动放到主线程中去执行)
        dispatch_queue_t queue = dispatch_get_main_queue();
        
        // 2.添加 任务 到主队列中 异步 执行
        dispatch_async(queue, ^{
            NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"-----下载图片2---%@", [NSThread currentThread]);
        });

        dispatch_async(queue, ^{
            NSLog(@"-----下载图片3---%@", [NSThread currentThread]);
        });

        dispatch_async(queue, ^{
            NSLog(@"-----下载图片4---%@", [NSThread currentThread]);
        });

        dispatch_async(queue, ^{
            NSLog(@"-----下载图片5---%@", [NSThread currentThread]);
        });

    }

    /**
     *  sync -- 主队列(不能用---会卡死)
     */
    - (void)syncMainQueue
    {
        NSLog(@"syncMainQueue----begin--");
        
        // 1.主队列(添加到主队列中的任务,都会自动放到主线程中去执行)
        dispatch_queue_t queue = dispatch_get_main_queue();
        
        // 2.添加 任务 到主队列中 异步 执行
        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片2---%@", [NSThread currentThread]);
        });

        dispatch_sync(queue, ^{
            NSLog(@"-----下载图片3---%@", [NSThread currentThread]);
        });

        
        NSLog(@"syncMainQueue----end--");
    }

    总结:

        全局并发队列 手动创建串行队列 主队列
    同步(sync)  

    1.没有开启新线程

    2.串行执行任务

    1.没有开启新线程

    2.串行执行任务

    1.没有开启新线程

    2.串行执行任务

    异步(async)  

    1.有开启新线程

    2.并发执行任务

    1.有开启新线程(只开1条)

    2.串行执行任务

    1.没有开启新线程

    2.串行执行任务

    注意:使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列

        3.8 GCD 线程间的通讯(子线程执行完耗时操作,回到主线程)

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {

        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        dispatch_async(queue, ^{
            NSLog(@"donwload---%@", [NSThread currentThread]);
            // 1.子线程下载图片
            NSURL *url = [NSURL URLWithString:@"http://img2.bdstatic.com/static/searchdetail/img/dragtip1_f3e8b97.png"];
            NSData *data = [NSData dataWithContentsOfURL:url];
            UIImage *image = [UIImage imageWithData:data];
            
            // 2.回到主线程设置图片
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"setting---%@ %@", [NSThread currentThread], image);
                [self.button setImage:image forState:UIControlStateNormal];
            });
        });
    }

    4、NSOperation

        简介:基于CGD(底层是GCD),比GCD多了一些简单实用的功能,使用更加面向对象

        语言:OC

        线程生命周期:自动管理

        使用频率:经常使用

  • 相关阅读:
    MVC设置默认页面
    MySQL_DBA整理
    解决git提交敏感信息(回退git版本库到某一个commit)
    并发数计算
    高并发下的 Nginx 优化与负载均衡
    PassengerNginxdebian快速部署Rails
    Linux+postfix+extmail+dovecot打造基于web页面的邮件系统
    2018.11.30软件更新公告
    2018.10.11软件更新公告
    2018.09.25软件更新公告
  • 原文地址:https://www.cnblogs.com/HOYF/p/5074571.html
Copyright © 2020-2023  润新知