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

时间:2022-05-06 16:12:35

      我在前面的博客中《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在项目中会经常会用到,应该需要熟练掌握。