iOS多线程开发——GCD的使用与多线程开发浅析

      我在前面的博客中《GCD实践——串行队列/并发队列与IOS多线程详解》中对iOS中的同步异步、串行并行做了较为详细的讲解。在之后的几篇GCD实践的博客中对GCD的使用也有较为详细的实现。但是我们要注意的是,那里用到的GCD是别人对苹果的原生GCD接口封装后的使用,虽然用起来更为方便,但是为了有全面的学习,我还是推荐去用苹果原生的GCD。该案例代码上传至 https://github.com/chenyufeng1991/MoreGCD 。代码中已经有部分注释对理解代码很有帮助。下面我来一一进行讲解。

只要是同步执行的任务,都会在当前线程执行,不会另开线程。
只要是异步任务执行的任务,都会另开线程,在别的线程执行。
同步操作会阻塞当前线程,直到block中的任务执行完毕,然后当前线程才会继续往下执行。(block在主线程中执行)
异步操作,当前线程会直接往下执行,不会阻塞当前线程。 (因为block在新线程中执行)

串行队列:一次只执行一个线程。
并行队列:一次可以执行多个线程。

(1)自己创建一个并发队列,并同步执行

    //dispatch_queue_t 也可以自己定义,如果要自定义,可以用dispatch_queue_create方法。
    //当然也可以使用系统提供的global_queue,main_queue
    dispatch_queue_t syncQueue = dispatch_queue_create("my.concurrent.syncQueue", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"1");
    dispatch_sync(syncQueue, ^{
        NSLog(@"2");

        [NSThread sleepForTimeInterval:3];
        NSLog(@"3");
    });
    
    NSLog(@"4");
    dispatch_release(syncQueue);//最好需要释放
建议该队列使用完后,进行release。

(2)自己创建一个并发队列,异步执行

    dispatch_queue_t asyncQueue = dispatch_queue_create("my.concurrent.asyncQueue", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"1");
    dispatch_async(asyncQueue, ^{
        NSLog(@"2");

        [NSThread sleepForTimeInterval:3];
        NSLog(@"3");
    });
    NSLog(@"4");
    dispatch_release(asyncQueue);


(3)自己创建一个串行队列,同步执行

    dispatch_queue_t syncQueue = dispatch_queue_create("my.serial.syncQueue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1");
    dispatch_sync(syncQueue, ^{
        NSLog(@"2");

        [NSThread sleepForTimeInterval:3];
        NSLog(@"3");
    });
    NSLog(@"4");
    dispatch_release(syncQueue);


(4)自己创建一个串行队列,异步执行

    dispatch_queue_t asyncQueue = dispatch_queue_create("my.serial.asyncQueue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1");
    //第一个参数是指定了一个GCD队列,第二个参数是分配事务到该队列。
    dispatch_async(asyncQueue, ^{
        NSLog(@"2");

        [NSThread sleepForTimeInterval:3];
        NSLog(@"3");
    });
    NSLog(@"4");
    dispatch_release(asyncQueue);


(5)关于系统提供的线程

dispatch_global_queue :并行队列

dispatch_private_queue:串行队列

dispatch_main_queue:主线程


以下代码是异步执行耗时操作,并更新UI的代码:

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //进入另一个线程,处理耗时的代码块

        dispatch_async(dispatch_get_main_queue(), ^{
            //返回主线程刷新

        });
    });


(6)一次性执行某个操作,并在应用生命周期内仅执行一次

    //在该应用声明周期内,下面的代码只会被执行一次。并且是线程安全的。
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"仅会被执行一次");
    });


(7)线程组,是一种同步机制,可以让某些线程先执行,某些线程最后执行,以控制线程的执行顺序。

    //GCD的高级用法 线程组;线程组和信号量机制都可以实现队列的同步。
   __block int i;
   __block int j;
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        i = 1;
    });

    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        j = 2;
    });

    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"%d",i+j);
    });

(8)线程的延迟执行

 NSLog(@"1");
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"延迟3s执行这里");
    });


(9)信号量,同步机制,控制线程执行流程。可以和操作系统中的信号量联系起来理解。

    //信号量
    /**
     *  创建一个信号量。参数指定信号量的起始值。这个数字是你可以访问的信号量,不需要先去增加它的数量(增加信号量也叫作发射信号量)。
     
     初始value = 0时,信号量--,小于0,wait线程阻塞。然后执行signal,信号量++,激活wait线程。
     *
     */
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);

    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        NSLog(@"chen");
    });

    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        NSLog(@"yu");
        dispatch_semaphore_signal(sema);
    });


(10)同一个线程中的不同任务实现同步。

使用dispatch_barrier_queue实现。注意dispatch_barrier_queue的同步控制和线程组、信号量的同步机制是不一样的,dispatch_barrier_queue是对于同一个队列中的不同任务而言的,线程组和信号量是对于不同线程而言的。

    //dispatch_barrier_async,对于同一个队列中的不同任务而言,在dispatch_barrier_async之前的先执行,在dispatch_barrier_async后面的后执行
    //如下面的代码所示:1和2的执行顺序不一定,但一定在dispatch_barrier_async之前执行,3和4的执行顺序不一定,但一定在dispatch_barrier_async之后执行。
    //注意dispatch_barrier_async的同步控制和线程组、信号量的同步机制粒度大小是不一样的,dispatch_barrier_async是对于同一个队列中的不同任务而言的,线程组和信号量是对于不同线程而言的。
    dispatch_queue_t queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"1");
    });

    dispatch_async(queue, ^{
        NSLog(@"2");
    });

    dispatch_barrier_async(queue, ^{
        NSLog(@"dispatch_barrier_async");
    });

    dispatch_async(queue, ^{
        NSLog(@"3");
    });

    dispatch_async(queue, ^{
        NSLog(@"4");
    });

(11)dispatch_apply是把某个代码块执行N遍。

    //dispatch_apply是把某个代码块执行N遍
    dispatch_apply(5, dispatch_get_global_queue(0, 0), ^(size_t index) {
        NSLog(@"%zu",index);
    });



   GCD在项目中会经常会用到,应该需要熟练掌握。


你可能感兴趣的:(iOS开发,iOS开发技术分享)