Quick Start Guide
- @synchronized
- NSLock 对象锁
- NSRecursiveLock 递归锁
- NSConditionLock 条件锁
- pthread_mutex 互斥锁
- dispatch_semaphore 信号量锁
- OSSpinLock
性能对比
这里只能反应单线程情况,不能反映多线程下的实际性能
Getting Started
1. @synchronized
@synchronized(obj) {
//这里obj指oc对象,一般为self
}
注意:加锁的代码量要少,oc对象在多个线程都是同一个对象
2. NSLock
//创建锁
NSLock *lock = [[NSLock alloc] init];
...
[lock lock];
//逻辑处理
[lock unlock];
注意:lock不能多次调用,会造成死锁
3. NSRecursiveLock
//死锁-递归
NSLock *lock = [[NSLock alloc] init];
dispatch_async(self.queue, ^{
static void (^method)(int value);
method = ^(int number) {
[lock lock];
//条件
method(number)
[lock unlock];
};
method(10);
});
//正确使用-递归
NSLock *lock = [[NSRecursiveLock alloc] init];
__block int num = 10;
dispatch_async(self.queue, ^{
static void (^method)(int value);
method = ^(int number) {
[lock lock];
//条件
method(--number)
[lock unlock];
};
method(num);
});
NSRecursiveLock在递归或者循环内(同一线程)使用不会造成死锁
4. NSConditionLock
NSConditionLock *lock = [[NSConditionLock alloc] init];
//线程1
dispatch_async(self.queue, ^{
for (int i=0;i<10;i++) {
[lock lock];
NSLog(@"%d",i);
[lock unlockWithCondition:5];
}
});
//线程2
dispatch_async(self.queue, ^{
[lock lockWhenCondition:5];
[lock unlock];
});
5. pthread_mutex
//引用
#include <pthread.h>
//通过设置attr类型可以设置递归锁,互斥锁等
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL)
__block pthread_mutex_t mutex;
pthread_mutex_init(&mutex,&attr);
dispatch_async(self.queue, ^{
pthread_mutex_lock(&mutex);
NSLog(@"thread 1");
pthread_mutex_unlock(&mutex);
});
dispatch_async(self.queue, ^{
pthread_mutex_lock(&mutex);
NSLog(@"thread 2");
pthread_mutex_unlock(&mutex);
});
此方法比较基础,如NSLock,NSConditionLock,,NSRecursiveLock底层实现都是用此方法实现
6. dispatch_semaphore
//创建信号量,并设置初始信号总量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_queue_t queue = dispatch_queue_create("testqueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
//模拟耗时操作
[NSThread sleepForTimeInterval:2];
//使总信号量减1,当信号总量为0时会一直等待,否则正常执行
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"thread 1");
//发送一个信号,让信号总量加1
dispatch_semaphore_signal(semaphore);
});
dispatch_async(queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"thread 2");
dispatch_semaphore_signal(semaphore);
});
7. OSSpinLock
//创建锁
lock = OS_SPINLOCK_INIT;
...
//加锁
OSSpinLockLock(&lock);
...
//解锁
OSSpinLockUnlock(&lock);
不推荐使用,如果一个低优先级的线程获得锁并访问共享资源,这时一个高优先级的线程也尝试获得这个锁,它会处于 spin lock 的忙等状态从而占用大量 CPU。此时低优先级线程无法与高优先级线程争夺 CPU 时间,从而导致任务迟迟完不成、无法释放 lock。这并不只是理论上的问题,libobjc 已经遇到了很多次这个问题了,于是苹果的工程师停用了 OSSpinLock。ios 10以后可以使用os_unfair_lock代替OSSpinLock