我在前面的博客中《GCD实践——串行队列/并发队列与IOS多线程详解》中对iOS中的同步异步、串行并行做了较为详细的讲解。在之后的几篇GCD实践的博客中对GCD的使用也有较为详细的实现。但是我们要注意的是,那里用到的GCD是别人对苹果的原生GCD接口封装后的使用,虽然用起来更为方便,但是为了有全面的学习,我还是推荐去用苹果原生的GCD。该案例代码上传至 https://github.com/chenyufeng1991/MoreGCD 。代码中已经有部分注释对理解代码很有帮助。下面我来一一进行讲解。
(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);
});
NSLog(@"1");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"延迟3s执行这里");
});
//信号量
/**
* 创建一个信号量。参数指定信号量的起始值。这个数字是你可以访问的信号量,不需要先去增加它的数量(增加信号量也叫作发射信号量)。
初始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);
});