线程安全是指多线程同时访问一块资源造成的数据安全问题。
OSSpinLock(自旋锁)
dispatch_semaphore(信号量)
pthread_mutex(互斥锁)
NSLock (内部封装了一个pthread_mutex)
NSCondition (条件锁)
NSRecursiveLock (递归锁)
NSConditionLock (借助 NSCondition 实现)
synchronized (关键字加锁)
(1)OSSpinLock
自旋锁的实现原理比较简单,就是死循环。当a线程获得锁以后,b线程想要获取锁就需要等待a线程释放锁。在没有获得锁期间,b线程会一直处于忙等的状态。如果a线程在临界区的执行时间过长,则b线程会消耗大量的cpu时间,不太划算。所以自旋锁在临界区执行时间比较短的环境效率比较高。
使用方法:需要导入 import
OSSpinLock lock = OS_SPINLOCK_INIT;
OSSpinLockLock(&lock); //加锁
需要加锁代码块
OSSpinLockUnlock(&lock);//解锁
(2)dispatch_semaphore
信号量:实现原理跟自旋锁有点不一样。它首先将信号量减一,并判断是否大于等于0,如果是则返回0,并继续执行后续代码,否则,使线程进入睡眠状态,让出cpu时间。直到信号量大于0或者超出时,则线程会被重新唤醒执行后续代码。
使用方法:dispatch_semaphore_t semaphore = dispatch_semaphore_creare(1);// 创建信号量
dispatch_semaphore_wait(semaphore);//判断信号量是否大于0,并使信号量减一
需要加锁的代码
dispatch_semaphore_signal(semaphore); //信号量加一
(3)pthread_mutex
互斥锁:和信号量的实现原理类似,也是阻塞线程并进入睡眠,需要进行上下文切换
使用方法:需要导入 import
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_NORMAL);
pthread_mutex_t lock;
pthread_mutex_init(&lock,&attr); //设置属性
pthread_mutex_lock(&lock); //上锁
需要执行代码块
pthread_mutex_unlock(&lock);//解锁
(4)NSLock
锁:NSLock在内部封装了一个 pthread_mutex,属性为 PTHREAD_MUTEX_ERRORCHECK
使用方法:NSLock* lock = [[NSLock alloc] init];//锁对象
[lock lock];//加锁
需要执行的代码
[lock unlock];
(5)NSCondition
条件锁:封装了一个互斥锁和条件变量。互斥锁保证线程安全,条件变量保证执行顺序。
使用方法:NSCondition* lock = [[NSCondition alloc] init];
[lock lock];//加锁
需要执行的代码
[lock unlock];//解锁
(6)NSRecursiveLock
递归锁:pthread_mutex(recursive)的封装
使用方法:NSRecursiveLock* lock = [[NSRecursive alloc]init];
[lock lock];//加锁
需要执行代码块
[lock unlock];
(7)NSConditionLock
条件锁:借助 NSCondition 实现,本质是生产-消费者模型
使用方法:NSConditonLock* lock = [[NSConditionLock alloc] init];
[lock lock];//加锁
需要执行的代码块
[lock unlock];
(8)synchronized
关键字加锁:一个对象层面的加锁,锁住了整个对象,底层使用了,互斥递归锁来实现。
使用方法:@sychronized(锁住对象){需要锁的代码};注意:锁定一份代码,只能用一把锁,用多把锁是无效的。
对以上各个锁进行1000000此的加锁解锁的空操作时间如下:
OSSpinLock: 46.15 ms
dispatch_semaphore: 56.50 ms
pthread_mutex: 178.28 ms
NSCondition: 193.38 ms
NSLock: 175.02 ms
pthread_mutex(recursive): 172.56 ms
NSRecursiveLock: 157.44 ms
NSConditionLock: 490.04 ms
@synchronized: 371.17 ms
OSSpinLock和dispatch_semaphore的效率远远高于其他。
@synchronized和NSConditionLock效率较差。
鉴于OSSpinLock的不安全,所以我们在开发中如果考虑性能的话,建议使用dispatch_semaphore。
如果不考虑性能,只是图个方便的话,那就使用@synchronized。