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

    线程生命周期:自动管理

    使用频率:经常使用

原文地址:https://www.cnblogs.com/HOYF/p/5074571.html