锁的种类
- 锁可以分为两大类,自旋锁和互斥锁
- 互斥锁:互斥 + 同步,两条线程同时处理任务,互斥:A走B不能走,同步:按照相应的顺序先后走,闲等
- 同步 = 互斥 + 顺序,相当于更加严厉的互斥
- 自旋锁:A走,B在死等,忙等
- 互斥锁:互斥 + 同步,两条线程同时处理任务,互斥:A走B不能走,同步:按照相应的顺序先后走,闲等
- NSRecursiveLock 同样具备递归性(解决了NSLock的无法递归性),但无法多线程
- @synchronized 具备多线程递归性(解决了NSrecursiveLock无法多线程),使用场景广泛
NSCondition
- NSCondition的对象实际上作为一个锁和一个线程检查器:
- 锁主要为了当检测条件时保护数据源,执行条件引发的任务
- 线程检查器主要是根据条件决定是否继续运行线程,即线程是否被阻塞
补充
读写锁实现
- 方法一、pthread
- 方法二、GCD
- 满足特性
- 多读单写
- 写 和 写 互斥
- 读 和 写 互斥
- 写的时候不能堵塞任务执行
- 栅栏函数 写(自定义的并发队列),下面的操作不能走,使用dispatch_barrier_async
- 读:多读 dispatch_sync 同步 多读(并发队列)
- 多读是线程和线程间多读,同时保证了读写互斥功能
举例
- 以下代码在运行时,因为多线程原因,导致打印数据紊乱
- 解决方案1:可以通过添加NSLock解决
- 核心的业务代码在testMethod(10)处,所以锁这里
- 注意:避免NSLock与业务代码锁在一起,保证业务代码块的安全
- NSLock可以多线程,但不具备递归性
- NSRecuresiveLock使用加锁,只能打印一次10~1
- NSRecuresiveLock递归锁不具备多线程性
- 因此使用@synchronized即可多线程又可递归 ```objectivec
(void)lg_testRecursive{ for (int i= 0; i<10; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
static void (^testMethod)(int);
testMethod = ^(int value){
[self.recursiveLock lock];
if (value > 0) {
NSLog(@"current value = %d",value);
testMethod(value - 1);
}
[self.recursiveLock unlock];
};
testMethod(10);
});
} } ```
NSCondition 跟信号量类似,相当于两把锁+信号量
- NSLock,遵循了NSLocking协议,底层封装了pthread_mutex_init(mutex, nil),调用pthread_mutex_lock
- NSRecuresiveLock,底层同样是对pthread_mutex_lock进行调用,与NSLock不同的是,其底层settype = PTHREAD_MUTEX_RECURSIVE
NSCondictionLock,底层也是封装了pthread_mutext_lock,额外添加了condition的条件pthread_cond_wait
NSCondictionLock
以下代码执行顺序3 -> 2 -> 1,2一定在1前面执行,满足条件才能执行,3没有条件控制,直接执行
- 底层封装了NSCondition