iOS-多线程-GCD

Posted iOS_满聪

tags:

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

一. 名词解释: 

1. 进程和线程

    进程是指在系统中正在运行的一个应用程序.每个进程之间都是独立的,每个进程均运行在期专用而且受到保护的内存空间中.

    线程是指一个进程想要执行任务,就必须要有线程.线程是进程的基本单元,一个进程的所有任务都在线程中进行.   

2. 具体的对多线程的描述请看 文顶顶大神的博客.http://www.cnblogs.com/wendingding/p/3805088.html

二. 队列

/** 队列: 用于存放任务.分为:串行队列和并行队列.
 1. 串行队列: 放到串行队列中的任务,GCD会FIFO(先进先出)的取出来一个,执行一个,然后取出来下一个,这样一个一个的执行.
 2. 并行队列: 放到并行队列中的任务,GCD也会FIFO的取出来,但不同的是,他取出来一个任务就会放到别的线程中,然后取出来一个又放到另一个线程中.由于取的动作很快,可以忽略不计,看起来,所有的任务都是一起执行的.不过需要注意,GCD会根据系统资源控制并行的数量.所以任务很多也不会然所有的任务都执行.
 */

三. 任务

/** 任务: 有两种执行方式,同步执行和异步执行.区别是是否会创建新的线程.
 1. 同步执行(sync): 会阻塞当前的线程并等待Block执行完毕,然后当前线程才会继续往下运行.
 2. 异步执行(async): 当前线程会直接往下执行,它不会阻塞当前线程.
 */

四.

    /** 获取主线程
     1. 所有的刷新UI界面的任务都要在主线程执行.
     2. 将消耗时间的任务放在别的线程中出来,尽量不要在主线程中处理.
     */
    dispatch_queue_t main_queue = dispatch_get_main_queue();
    NSLog(@"main_queue:\\n %@",main_queue);
    
    /** 自己创建的队列  dispatch_queue_create
     参数1: 第一个参数是标识符.用于DEBUG的时候标志唯一的队列,可以为空.
     参数2: 第二个参数用来表示创建的队列是串行的还是并行的.传入DISPATCH_QUEUE_SERIAL或者NULL表示创建的是串行队列.传入DISPATCH_QUEUE_CONCURRENT表示创建的并行队列. (SERIAL--> serial连续的/CONCURRENT--> concurrent,并发的,一致的)
     */
    
    // 创建串行队列
    dispatch_queue_t serialQueue = dispatch_queue_create(nil, NULL);
    NSLog(@"serialQueue:\\n %@",serialQueue);

    // 创建并行队列: 这应该是唯一一个并行队列,只要是并行任务一般都加入到这个队列
    dispatch_queue_t concurrentQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"concurrentQueue:\\n %@",concurrentQueue);
    
    
    // 创建任务
    /** 同步任务 (sync)
     1. 不会另外开辟线程.
     */
    dispatch_sync( serialQueue, ^{
       
        for (int i = 0; i < 10000; i ++)
        {
            NSLog(@"同步任务: \\n%@",[NSThread currentThread]);
        }
    });
    
    /** 同步任务 (async)
     1. 会另外开辟线程.
     */
    dispatch_async(serialQueue, ^{
        NSLog(@"异步任务: %@",[NSThread currentThread]);
    });

五. 例子介绍

NSLog(@"之前==> %@",[NSThread currentThread]);
    
    dispatch_sync(dispatch_get_main_queue(), ^{
        
        NSLog(@"sync==> %@",[NSThread currentThread]);
    });
    
    NSLog(@"之后==> %@",[NSThread currentThread]);
    
    
    /** 解释
     1. 只会打印第一句:之前==> <NSThread: 0x7fe66b700610>{number = 1, name = main} ,然后主线程就卡死了,你可以在界面上放一个按钮,你就会发现点不了了。
     2. 打印完第一句,dispatch_sync(因为是一个同步任务,会阻塞当前的线程)会阻塞当前的主线程,然后把Block中的任务放到main_queue中,main_queue中的任务会被取出来放到主线程中执行,但主线程种鸽时候已经被阻塞了,所以Block种鸽的任务就不能完成,它不完成,dispatch_sync就会一直阻塞主线程.导致主线程一直卡死.这就是死锁现象.
     */
 dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    
    NSLog(@"输出1.之前==> %@",[NSThread currentThread]);
    
    dispatch_async(queue, ^{
        
        NSLog(@"输出2.sync之前==> %@",[NSThread currentThread]);
        
        dispatch_sync(queue, ^{
            
            NSLog(@"输出3.sync==> %@",[NSThread currentThread]);
        });
        NSLog(@"输出4.sync之后==> %@",[NSThread currentThread]);
    });
    
    NSLog(@"输出5.之后==> %@",[NSThread currentThread]);
    
    /** 解释
     1. 当前线程为默认的主线程
     2. 输出结果为,输出1,输出5和输出2 执行了输出.输出3和输出4没有被执行.
     3. 按照执行顺序分析.
        (1)我们创建的队列queue是一个串行队列(DISPATCH_QUEUE_SERIAL).串行队列的特点是,所持有的任务会取出一个执行一个.当前任务没有执行完,下一个任务不会被执行.
        (2)打印出输出1.
        (3)在queue队列中开启了一个异步任务(async).异步任务的特点是,当前的线程不会被阻塞.所以有了两条线程,一条是主线程中执行输出5.另一条是在新开辟的queue线程中执行输出2.
        (4)在开辟的queue线程中,又执行了一个同步的任务(sync),同步任务的特点是执行一个任务会阻塞当前的线程.当前的线程是queue,已经被阻塞了.又要求它去执行下一个任务.就造成了死锁现象.所以 sync 所在的线程被卡死了,输出3和输出4自然就不会打印了.
     */

六.队列组可以将很多队列添加到一个组里,这样做的好处是,当这个组里所有的任务都执行完了,队列组会通过一个方法通知我们。

    //1. 创建队列组
    dispatch_group_t group = dispatch_group_create();
    
    //2. 创建队列  dispatch_get_global_queue 会获取一个全局队列,我们姑且理解为系统为我们开启的一些全局线程。我们用priority指定队列的优先级,而flag作为保留字段备用(一般为0)。

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //3. 多次使用队列中的方法执行任务,只有异步任务
    //3.1 执行三次循环
    dispatch_group_async(group, queue, ^{
       
        for (int i = 0; i < 3; i ++)
        {
            NSLog(@"group-01 - %@",[NSThread currentThread]);
        }
    });
    
    //3.2 主队列执行8次循环
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
       
        for (int i = 0; i < 8; i ++)
        {
            NSLog(@"group-02 - %@",[NSThread currentThread]);
        }
    });
    
    //3.3 执行5次循环
    dispatch_group_async(group, queue, ^{
        
        for (int i = 0; i < 5; i ++)
        {
            NSLog(@"group-03 - %@",[NSThread currentThread]);
        }
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
       
        NSLog(@"完成 - %@",[NSThread currentThread]);
    });

 

以上是关于iOS-多线程-GCD的主要内容,如果未能解决你的问题,请参考以下文章

ios多线程操作—— GCD核心概念

iOS 多线程:『GCD』详尽总结

ios多线程 -- GCD介绍

iOS 多线程-GCD

iOS多线程编程(四)------ GCD(Grand Central Dispatch)

iOS开发中的gcd多线程tips