由于之前开发中用到了锁这个东西,加上这个知识在之前的项目中用之甚少,所以对于此想做一下在百度网上文章过程中的再一次了解中的简单总结。
基本思路就三点:1:iOS中有几种常用的锁
2:几种锁的性能及个别锁的简单使用
3:对于常用锁中互斥锁(NSLock 和@synchronized)和自旋锁的区别
首先要知道锁是一种同步机制,用于在存在多线程环境中实施对资源访问限制。其中有互斥锁、对象所、递归锁、条件锁、自旋锁、信号量实现加锁这几种。他们分别有自己的处理机制故而性能也不尽相同,具体性能由快到慢简单总结如下:
OSSpinLock(性能最高但不再安全 具体使用方式也无须过于了解,iOS SDK里无OSSpinLock头文件可导 用不了)>
dispatch_semaphore (信号量加锁)> pthread_mutex (互斥锁)> NSLock (对象锁 也是互斥锁的一种)>NSRecursiveLock (递归锁) >NSConditionLock (条件锁)> @synchronized (互斥锁)
以下列举简单使用的买票实例 http://www.jianshu.com/p/1e59f0970bf5 (从此文章中粘入几个实例引用便于自己观看回顾)
@synchronized 是一个 OC 层面的锁, 主要是通过牺牲性能换来语法上的简洁,@synchronized 后面需要紧跟一个 OC 对象,它实际上是把这个对象当做锁来使用。这是通过一个哈希表来实现的,OC 在底层使用了一个互斥锁的数组(你可以理解为锁池),通过对对象去哈希值来得到对应的互斥锁。
//设置票的数量为5
_tickets = 5;
//线程1
dispatch_async(self.concurrentQueue, ^{
[self saleTickets];
});
//线程2
dispatch_async(self.concurrentQueue, ^{
[self saleTickets];
});
- (void)saleTickets
{
while (1) {
@synchronized(self) {
[NSThread sleepForTimeInterval:1];
if (_tickets > 0) {
_tickets--;
NSLog(@"剩余票数= %ld, Thread:%@",_tickets,[NSThread currentThread]);
} else {
NSLog(@"票卖完了 Thread:%@",[NSThread currentThread]);
break;
}
}
}
}
NSLock 互斥锁只是在内部封装了一个 pthread_mutex,属性为PTHREAD_MUTEX_ERRORCHECK,它会损失一定性能换来错误提示。不能多次调用lock
//设置票的数量为5
_tickets = 5;
//创建锁
_mutexLock = [[NSLock alloc] init];
//线程1
dispatch_async(self.concurrentQueue, ^{
[self saleTickets];
});
//线程2
dispatch_async(self.concurrentQueue, ^{
[self saleTickets];
});
- (void)saleTickets
{
while (1) {
[NSThread sleepForTimeInterval:1];
//加锁
[_mutexLock lock];
if (_tickets > 0) {
_tickets--;
NSLog(@"剩余票数= %ld, Thread:%@",_tickets,[NSThread currentThread]);
} else {
NSLog(@"票卖完了 Thread:%@",[NSThread currentThread]);
break;
}
//解锁
[_mutexLock unlock];
}
}
NSConditionLock (条件锁)
//主线程中
NSConditionLock *theLock = [[NSConditionLock alloc] init];
//线程1
dispatch_async(self.concurrentQueue, ^{
for (int i=0;i<=3;i++)
{
[theLock lock];
NSLog(@"thread1:%d",i);
sleep(1);
[theLock unlockWithCondition:i];
}
});
//线程2
dispatch_async(self.concurrentQueue, ^{
[theLock lockWhenCondition:2];
NSLog(@"thread2");
[theLock unlock];
});
NSRecursiveLock (递归锁)
//创建锁
_rsLock = [[NSRecursiveLock alloc] init];
//线程1
dispatch_async(self.concurrentQueue, ^{
static void(^TestMethod)(int);
TestMethod = ^(int value)
{
[_rsLock lock];
if (value > 0)
{
[NSThread sleepForTimeInterval:1];
TestMethod(value--);
}
[_rsLock unlock];
};
TestMethod(5);
});
pthread_mutex 互斥锁 需要导入#include <pthread.h>
__block pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
//线程1
dispatch_async(self.concurrentQueue), ^{
pthread_mutex_lock(&mutex);
NSLog(@"任务1");
sleep(2);
pthread_mutex_unlock(&mutex);
});
//线程2
dispatch_async(self.concurrentQueue), ^{
sleep(1);
pthread_mutex_lock(&mutex);
NSLog(@"任务2");
pthread_mutex_unlock(&mutex);
});
dispatch_semaphore 信号量实现加锁
// 创建信号量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务1");
sleep(10);
dispatch_semaphore_signal(semaphore);
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务2");
dispatch_semaphore_signal(semaphore);
});
自旋锁
bool lock = false; // 一开始没有锁上,任何线程都可以申请锁
do {
while(test_and_set(&lock); // test_and_set 是一个原子操作
Critical section // 临界区
lock = false; // 相当于释放锁,这样别的线程可以进入临界区
Reminder section // 不需要锁保护的代码
}
对于自旋锁和互斥锁二者的区别
相同点在于:都能保证同一时间只有一个线程访问共享资源 保证安全
不同点在于:1自旋锁效率高于互斥锁
2如果共享数据已有其他线程加锁了,互斥锁会使线程进入休眠状态等待解锁,如果资源解锁,则线程被唤醒。而自旋锁会使线程以死循环的方式等待解锁,如果资源解锁,则另一个线程会立即执行
PS:atomic内部为互斥锁 ->其中setter方法中多了个@synchronized(self){} <-等当前对象操作完毕会合成确定值