iOS开发中多线程间关于锁的使用

为什么需要使用锁,当然熟悉多线程的你,自然不会感到陌生。

那你在代码中是否很好的使用了锁的机制呢?你又知道几种实现锁的方法呢?

main.m

 1 int main(int argc, const char * argv[]) {
 2     @autoreleasepool {
 3         //普通用法;会看到线程1锁住之后,线程2会一直等待,直到线程1执行完,线程2才执行
 4         NSLog(@"使用NSLock(普通锁;已实现NSLocking协议)实现锁");
 5         [LockByNSLock executeLock];
 6
 7         NSLog(@"使用Synchronized指令实现锁");
 8         [LockBySynchronized executeLock];
 9
10         NSLog(@"使用C语言的pthread_mutex_t实现锁");
11         [LockByPthreadMutexT executeLock];
12
13         NSLog(@"使用GCD的dispatch_semaphore_t(信号量)实现锁");
14         [LockByDispatchSemaphoreT executeLock];
15
16
17         //高级用法
18         NSLog(@"使用NSRecursiveLock(递归锁;已实现NSLocking协议)实现锁;可以在递归场景中使用。如果使用NSLock,会出现死锁");
19         [LockByNSRecursiveLock executeLock];
20
21         NSLog(@"使用NSConditionLock(条件锁;已实现NSLocking协议)实现锁;可以在需要符合条件才进行锁操作的场景中使用");
22         [LockByNSConditionLock executeLock];
23
24         NSLog(@"使用NSDistributedLock(分布式锁;区别其他锁类型,它没有实现NSLocking协议)实现锁;它基于文件系统,会自动创建用于标识的临时文件或文件夹,执行完后自动清除临时文件或文件夹;可以在多个进程或多个程序之间需要构建互斥的场景中使用");
25         [LockByNSDistributedLock executeLock]; //这里看不出效果,具体测试应该是线程1和线程2同时进行,即是在多个进程或多个程序之间需要构建互斥的场景下
26     }
27     return 0;
28 }

今天一起来探讨一下 iOS 中实现锁的几种不同方式,在这之前我们先构建一个测试用的类,假想它是我们的一个共享资源,firstMethod 与 secondMethod 是互斥的,代码如下:

 1 #import "TestObj.h"
 2
 3 @implementation TestObj
 4
 5 - (void)firstMethod {
 6     NSLog(@"Execute %@", NSStringFromSelector(_cmd));
 7 }
 8
 9 - (void)secondMethod {
10     NSLog(@"Execute %@", NSStringFromSelector(_cmd));
11 }
12
13 @end

1.使用 NSLock 实现的锁

 1 #import "LockByNSLock.h"
 2 #import "TestObj.h"
 3
 4 @implementation LockByNSLock
 5
 6 + (void)executeLock {
 7     //主线程中
 8     TestObj *obj = [[TestObj alloc] init];
 9     NSLock *lock = [[NSLock alloc] init];
10
11     //线程1
12     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
13         [lock lock];
14         [obj firstMethod];
15         sleep(2); //线程1执行挂起2秒
16         [lock unlock];
17     });
18
19     //线程2
20     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
21         sleep(1); //线程2执行挂起1秒,以保证一定是线程1先执行
22         [lock lock];
23         [obj secondMethod];
24         [lock unlock];
25     });
26 }
27
28 @end

看到打印的结果了吗,你会看到线程1锁住之后,线程2会一直等待走到线程1将锁置为 unlock 后,才会执行 secondMethod 方法。

NSLock 是 Cocoa 提供给我们最基本的锁对象,这也是我们经常所使用的,除 lock 和 unlock 方法外,NSLock 还提供了 tryLock 和 lockBeforeDate: 两个方法,前一个方法会尝试加锁,如果锁不可用(已经被锁住),并不会阻塞线程,直接返回 NO。lockBeforeDate: 方法会在所指定 Date 之前尝试加锁,如果在指定时间之前都不能加锁,则返回 NO。

2.使用 synchronized 关键字构建的锁

当然在 Objective-C 中你还可以用 @synchronized 指令快速的实现锁:

 1 #import "LockBySynchronized.h"
 2 #import "TestObj.h"
 3
 4 @implementation LockBySynchronized
 5
 6 + (void)executeLock {
 7     //主线程中
 8     TestObj *obj = [[TestObj alloc] init];
 9
10     //线程1
11     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
12         @synchronized(obj) {
13             [obj firstMethod];
14             sleep(2); //线程1执行挂起2秒
15         }
16     });
17
18     //线程2
19     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
20         @synchronized(obj) {
21             sleep(1); //线程2执行挂起1秒,以保证一定是线程1先执行
22             [obj secondMethod];
23         }
24     });
25 }
26
27 @end

@synchronized 指令使用的 obj 为该锁的唯一标识,只有当标识相同时,才为满足互斥,如果线程2中的@synchronized(obj) 改为@synchronized(other) 时,线程2就不会被阻塞,@synchronized 指令实现锁的优点就是我们不需要在代码中显式的创建锁对象,便可以实现锁的机制,但作为一种预防措施,@synchronized 块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。

3.使用C语言的 pthread_mutex_t 实现的锁

 1 #import "LockByPthreadMutexT.h"
 2 #import "TestObj.h"
 3 #include <pthread.h>
 4
 5 @implementation LockByPthreadMutexT
 6
 7 + (void)executeLock {
 8     //主线程中
 9     TestObj *obj = [[TestObj alloc] init];
10     __block pthread_mutex_t mutex;
11     pthread_mutex_init(&mutex, NULL);
12
13     //线程1
14     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
15         pthread_mutex_lock(&mutex);
16         [obj firstMethod];
17         sleep(2); //线程1执行挂起2秒
18         pthread_mutex_unlock(&mutex);
19     });
20
21     //线程2
22     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
23         sleep(1); //线程2执行挂起1秒,以保证一定是线程1先执行
24         pthread_mutex_lock(&mutex);
25         [obj secondMethod];
26         pthread_mutex_unlock(&mutex);
27     });
28 }
29
30 @end

pthread_mutex_t 定义在pthread.h,所以记得 #include

4.使用 GCD 来实现的”锁”
以上代码构建多线程我们就已经用到了 GCD 的 dispatch_async 方法,其实在 GCD 中也已经提供了一种信号机制,使用它我们也可以来构建一把”锁”

从本质意义上讲,信号量与互斥锁是有区别:

(1)作用域

信号量:进程间或线程间(linux 仅线程间)

互斥锁:线程间

(2)上锁时

信号量:只要信号量的 value 大于0,其他线程就可以 sem_wait 成功,成功后信号量的 value 减一。若 value 值不大于0,则 sem_wait 阻塞,直到 sem_post 释放后 value 值加一。一句话,信号量的 value>=0。

互斥锁:只要被锁住,其他任何线程都不可以访问被保护的资源。如果没有锁,获得资源成功,否则进行阻塞等待资源可用。一句话,线程互斥锁的 vlaue 可以为负数。

 1 #import "LockByDispatchSemaphoreT.h"
 2 #import "TestObj.h"
 3
 4 @implementation LockByDispatchSemaphoreT
 5
 6 + (void)executeLock {
 7     //主线程中
 8     TestObj *obj = [[TestObj alloc] init];
 9     dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
10
11     //线程1
12     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
13         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
14         [obj firstMethod];
15         sleep(2); //线程1执行挂起2秒
16         dispatch_semaphore_signal(semaphore);
17     });
18
19     //线程2
20     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
21         sleep(1); //线程2执行挂起1秒,以保证一定是线程1先执行
22         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
23         [obj secondMethod];
24         dispatch_semaphore_signal(semaphore);
25     });
26 }
27
28 @end

至于代码产生的效果当然和前面的是一模一样的,当然锁大多数情况下也是配合多线程一起使用的。

锁的高级用法

1.NSRecursiveLock递归锁

平时我们在代码中使用锁的时候,最容易犯的一个错误就是造成死锁,而容易造成死锁的一种情形就是在递归或循环中,如下代码:

 1 #import "LockByNSRecursiveLock.h"
 2 #import "TestObj.h"
 3
 4 @implementation LockByNSRecursiveLock
 5
 6 + (void)executeLock {
 7     //主线程中
 8     TestObj *obj = [[TestObj alloc] init];
 9     //NSLock *lock = [[NSLock alloc] init]; //NSLock在递归场景会出现死锁的情况,这里就得用NSRecursiveLock(递归锁)
10     NSRecursiveLock *lock = [[NSRecursiveLock alloc] init];
11
12     //线程1
13     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
14         static void(^recursiveMethod)(NSUInteger);
15         recursiveMethod = ^(NSUInteger val) {
16             [lock lock];
17             if (val > 0) {
18                 NSLog(@"递归中,val的值为:%lu", (unsigned long)val);
19                 [obj firstMethod];
20                 sleep(2); //线程1执行挂起2秒
21                 recursiveMethod(val-1);
22             }
23             [lock unlock];
24         };
25
26         recursiveMethod(5);
27     });
28
29     //线程2
30     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
31         sleep(1); //线程2执行挂起1秒,以保证一定是线程1先执行
32         [lock lock];
33         [obj secondMethod];
34         [lock unlock];
35     });
36 }
37
38 @end

以上的代码中,就是一种典型的死锁情况,因为在线程1中的递归 block 中,锁会被多次的 lock,所以自己也被阻塞了,由于以上的代码非常的简短,所以很容易能识别死锁,但在较为复杂的代码中,就不那么容易发现了,那么如何在递归或循环中正确的使用锁呢?此处的 lock 变量如果换用 NSRecursiveLock 对象,问题便得到解决了,NSRecursiveLock 类定义的锁可以在同一线程多次 lock,而不会造成死锁。递归锁会跟踪它被多少次 lock。每次成功的 lock 都必须平衡调用 unlock 操作。只有所有的锁住和解锁操作都平衡的时候,锁才真正被释放给其他线程获得。

2.NSConditionLock 条件锁

当我们在使用多线程的时候,有时一把只会 lock 和 unlock 的锁未必就能完全满足我们的使用。因为普通的锁只能关心锁与不锁,而不在乎用什么钥匙才能开锁,而我们在处理资源共享的时候,多数情况是只有满足一定条件的情况下才能打开这把锁:

 1 #import "LockByNSConditionLock.h"
 2 #import "TestObj.h"
 3
 4 @implementation LockByNSConditionLock
 5
 6 + (void)executeLock {
 7     //主线程中
 8     TestObj *obj = [[TestObj alloc] init];
 9     NSConditionLock *lock = [[NSConditionLock alloc] init];
10
11     //线程1
12     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
13         for (NSUInteger i=0; i<3; i++) {
14             [lock lock];
15             NSLog(@"循环中,i的值为:%lu", (unsigned long)i);
16             [obj firstMethod];
17             sleep(2); //线程1执行挂起2秒
18             [lock unlockWithCondition:i];
19         }
20     });
21
22     //线程2
23     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
24         sleep(1); //线程2执行挂起1秒,以保证一定是线程1先执行
25         //[lock lockWhenCondition:2]; //需要标识为2的钥匙才能进行加锁操作,这里等待线程1对lock的循环操作达到它需要的加锁条件;如果最终不符合条件(例如:线程1的条件判断是i<4时),将阻塞线程内容向下执行;这里就得用tryLockWhenCondition:方法控制
26         //[obj secondMethod];
27         //[lock unlock];
28
29         BOOL isLocked = [lock tryLockWhenCondition:2];
30         [obj secondMethod];
31         if (isLocked) { //加锁解锁必须成对操作,否则会报错
32             [lock unlock];
33         }
34     });
35 }
36
37 @end

在线程1中的加锁使用了 lock,所以是不需要条件的,所以顺利的就锁住了,但在 unlock 的使用了一个整型的条件,它可以开启其他线程中正在等待这把钥匙的临界地,而线程2则需要一把被标识为2的钥匙,所以当线程1循环到最后一次的时候,才最终打开了线程2中的阻塞。但即便如此,NSConditionLock 也跟其他的锁一样,是需要 lock 与 unlock 对应的,只是 lock,lockWhenCondition: 与 unlock,unlockWithCondition: 是可以随意组合的,当然这是与你的需求相关的。

3.NSDistributedLock 分布式锁

以上所有的锁都是在解决多线程之间的冲突,但如果遇上多个进程或多个程序之间需要构建互斥的情景该怎么办呢?这个时候我们就需要使用到 NSDistributedLock 了,从它的类名就知道这是一个分布式的 Lock,NSDistributedLock 的实现是通过文件系统的,所以使用它才可以有效的实现不同进程之间的互斥,但 NSDistributedLock 并非继承于 NSLock,它没有 lock 方法,它只实现了 tryLock, unlock, breakLock,所以如果需要 lock 的话,你就必须自己实现一个 tryLock 的轮询,下面通过代码简单的演示一下吧:

 1 #import "LockByNSDistributedLock.h"
 2 #import "TestObj.h"
 3
 4 @implementation LockByNSDistributedLock
 5
 6 + (void)executeLock {
 7     //主线程中
 8     TestObj *obj = [[TestObj alloc] init];
 9     NSDistributedLock *lock = [[NSDistributedLock alloc] initWithPath:@"/Users/Kenmu/Desktop/Temp/LockByNSDistributedLock"];
10
11     //线程1
12     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
13         [lock breakLock];
14         [lock tryLock];
15         [obj firstMethod];
16         sleep(5); //线程1执行挂起5秒
17         [lock unlock];
18     });
19
20     //线程2
21     dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
22         while (![lock tryLock]) {
23             NSLog(@"Waiting...");
24             sleep(1);
25         }
26         [obj secondMethod];
27         [lock unlock];
28     });
29 }
30
31 @end

实际场景应该如下:

程序A:

1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
2     lock = [[NSDistributedLock alloc] initWithPath:@"/Users/Kenmu/Desktop/earning__"];
3     [lock breakLock];
4     [lock tryLock];
5     sleep(10);
6     [lock unlock];
7     NSLog(@"appA: OK");
8 });

程序B:

1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
2     lock = [[NSDistributedLock alloc] initWithPath:@"/Users/Kenmu/Desktop/earning__"];
3     while (![lock tryLock]) {
4         NSLog(@"appB: waiting");
5         sleep(1);
6     }
7     [lock unlock];
8     NSLog(@"appB: OK");
9 });

先运行程序 A,然后立即运行程序 B,根据打印你可以清楚的发现,当程序 A 刚运行的时候,程序 B 一直处于等待中,当大概10秒过后,程序 B 便打印出了 appB:OK 的输出,以上便实现了两上不同程序之间的互斥。/Users/Kenmu/Desktop/earning __是一个文件或文件夹的地址,如果该文件或文件夹不存在,那么在 tryLock 返回 YES 时,会自动创建该文件/文件夹。在结束的时候该文件/文件夹会被清除,所以在选择的该路径的时候,应该选择一个不存在的路径,以防止误删了文件。

结果:

 1 2015-05-15 00:29:43.046 OCLock[1675:61800] 使用NSLock(普通锁;已实现NSLocking协议)实现锁
 2 2015-05-15 00:29:43.047 OCLock[1675:61800] Execute firstMethod
 3 2015-05-15 00:29:46.055 OCLock[1675:61800] Execute secondMethod
 4 2015-05-15 00:29:46.055 OCLock[1675:61800] 使用Synchronized指令实现锁
 5 2015-05-15 00:29:46.055 OCLock[1675:61800] Execute firstMethod
 6 2015-05-15 00:29:49.060 OCLock[1675:61800] Execute secondMethod
 7 2015-05-15 00:29:49.061 OCLock[1675:61800] 使用C语言的pthread_mutex_t实现锁
 8 2015-05-15 00:29:49.061 OCLock[1675:61800] Execute firstMethod
 9 2015-05-15 00:29:52.067 OCLock[1675:61800] Execute secondMethod
10 2015-05-15 00:29:52.067 OCLock[1675:61800] 使用GCD的dispatch_semaphore_t(信号量)实现锁
11 2015-05-15 00:29:52.068 OCLock[1675:61800] Execute firstMethod
12 2015-05-15 00:29:55.078 OCLock[1675:61800] Execute secondMethod
13 2015-05-15 00:29:55.079 OCLock[1675:61800] 使用NSRecursiveLock(递归锁;已实现NSLocking协议)实现锁;可以在递归场景中使用。如果使用NSLock,会出现死锁
14 2015-05-15 00:29:55.079 OCLock[1675:61800] 递归中,val的值为:5
15 2015-05-15 00:29:55.079 OCLock[1675:61800] Execute firstMethod
16 2015-05-15 00:29:57.080 OCLock[1675:61800] 递归中,val的值为:4
17 2015-05-15 00:29:57.080 OCLock[1675:61800] Execute firstMethod
18 2015-05-15 00:29:59.083 OCLock[1675:61800] 递归中,val的值为:3
19 2015-05-15 00:29:59.084 OCLock[1675:61800] Execute firstMethod
20 2015-05-15 00:30:01.089 OCLock[1675:61800] 递归中,val的值为:2
21 2015-05-15 00:30:01.089 OCLock[1675:61800] Execute firstMethod
22 2015-05-15 00:30:03.095 OCLock[1675:61800] 递归中,val的值为:1
23 2015-05-15 00:30:03.095 OCLock[1675:61800] Execute firstMethod
24 2015-05-15 00:30:06.106 OCLock[1675:61800] Execute secondMethod
25 2015-05-15 00:30:06.106 OCLock[1675:61800] 使用NSConditionLock(条件锁;已实现NSLocking协议)实现锁;可以在需要符合条件才进行锁操作的场景中使用
26 2015-05-15 00:30:06.107 OCLock[1675:61800] 循环中,i的值为:0
27 2015-05-15 00:30:06.107 OCLock[1675:61800] Execute firstMethod
28 2015-05-15 00:30:08.112 OCLock[1675:61800] 循环中,i的值为:1
29 2015-05-15 00:30:08.113 OCLock[1675:61800] Execute firstMethod
30 2015-05-15 00:30:10.115 OCLock[1675:61800] 循环中,i的值为:2
31 2015-05-15 00:30:10.115 OCLock[1675:61800] Execute firstMethod
32 2015-05-15 00:30:13.121 OCLock[1675:61800] Execute secondMethod
33 2015-05-15 00:30:13.121 OCLock[1675:61800] 使用NSDistributedLock(分布式锁;区别其他锁类型,它没有实现NSLocking协议)实现锁;它基于文件系统,会自动创建用于标识的临时文件或文件夹,执行完后自动清除临时文件或文件夹;可以在多个进程或多个程序之间需要构建互斥的场景中使用
34 2015-05-15 00:30:13.127 OCLock[1675:61800] Execute firstMethod
35 2015-05-15 00:30:18.129 OCLock[1675:61800] Execute secondMethod
时间: 2024-10-04 19:09:42

iOS开发中多线程间关于锁的使用的相关文章

iOS开发中多线程基础

耗时操作演练 代码演练 编写耗时方法 - (void)longOperation { for (int i = 0; i < 10000; ++i) { NSLog(@"%@ %d", [NSThread currentThread], i); } } 直接调用耗时方法 // 1> 直接调用耗时方法 [self longOperation]; 运行測试效果 在后台运行耗时方法 // 2> 在后台运行耗时方法 [self performSelectorInBackgro

IOS开发中多线程的使用

一.创建多线程的五种方式 1.开启线程的方法一 NSThread * thread=[[NSThread alloc] initWithTarget:self selector:@selector(_update) object:nil]; 2.开启线程的方法二 [NSThread detachNewThreadSelector:@selector(_update) toTarget:self withObject:nil]; 3.开启线程的方法三 [self performSelectorIn

iOS开发中的gcd多线程tips

iOS开发中的gcd多线程tips 我们经常用到的: dispatch_async(dispatch_get_global_queue(0, 0), ^{ // 处理耗时操作的代码块 //通知主线程刷新 dispatch_async(dispatch_get_main_queue(), ^{ //回调或者说是通知主线程刷新 }); }); 其中main_queue是系统默认的串行队列,global_queue是系统默认的并行队列. 什么是串行队列(Serial)? 创建任意个数的串行队列,每个队

深入理解 iOS 开发中的锁

来源:伯乐在线 - 夏天然后 链接:http://ios.jobbole.com/89474/ 点击 → 申请加入伯乐在线专栏作者 摘要 本文的目的不是介绍 iOS 中各种锁如何使用,一方面笔者没有大量的实战经验,另一方面这样的文章相当多,比如 iOS中保证线程安全的几种方式与性能对比.iOS 常见知识点(三):Lock.本文也不会详细介绍锁的具体实现原理,这会涉及到太多相关知识,笔者不敢误人子弟. 本文要做的就是简单的分析 iOS 开发中常见的几种锁如何实现,以及优缺点是什么,为什么会有性能上

iOS开发中GCD在多线程方面的理解

GCD为Grand Central Dispatch的缩写. Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法.在Mac OS X 10.6雪豹中首次推出,并在最近引入到了iOS4.0. GCD是一个替代诸如NSThread等技术的很高效和强大的技术.GCD完全可以处理诸如数据锁定和资源泄漏等复杂的异步编程问题. GCD可以完成很多事情,但是这里仅关注在iOS应用中实现多线程所需的一些基础知识. 在开始之前,需要理解是要提供给GCD队列的是代

ios开发中 线程、进程即多线程简单介绍

本文转自:原文http://www.cnblogs.com/wendingding/p/3805088.html 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcode,系统就会分别启动2个进程 通过“活动监视器”可以查看Mac系统中所开启的进程 2.什么是线程 1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程) 线程是进程的基本执行单元,一个进程(程序)的所有任务都在线

iOS开发之多线程编程

iOS开发之多线程编程 1. 多线程简述 1.1什么是多线程? 解决的问题? 多线程是指,编程中在主线程之外开辟的新线程,用于处理一些耗时的.并发的任务.使用多线程可以避免主线程的阻塞,也对一个线程不容易实现的任务提供了思路.在多线程的知识中也涉及队列,锁等概念. 在这里科普一下队列的概念,队列:是管理线程的,相当于线程池,能管理线程什么时候执行.队列分为串行队列和并行队列. 串行队列:队列中的线程按顺序执行(不会同时执行) 并行队列:队列中的线程会并发执行,可能会有一个疑问,队列不是先进先出吗

iOS开发之多线程技术——GCD篇

本篇将从四个方面对iOS开发中GCD的使用进行详尽的讲解: 一.什么是GCD 二.我们为什么要用GCD技术 三.在实际开发中如何使用GCD更好的实现我们的需求 一.Synchronous & Asynchronous 同步 & 异步 二.Serial Queues & Concurrent Queues 串行 & 并发 三.Global Queues全局队列 四.Main Queue主队列 五.同步的作用 六.dispatch_time延迟操作 七.线程安全(单例dispa

iOS开发之多线程技术——NSOperation篇

本篇将从四个方面对iOS开发中使用到的NSOperation技术进行讲解: 一.什么是NSOperation 二.我们为什么使用NSOperation 三.在实际开发中如何使用NSOperation 1.自定义NSOperation 2.NSOperation的基本使用 3.NSOperation实现线程间通信 1)利用代理进行消息传递 2)利用通知实现消息传递 3)利用block进行消息传递 四.与GCD比较 一.什么是NSOperation NSOperation是一个抽象的基类,表示一个独