多线程的安全隐患以及队列组和线程锁
多线程确实可以大大提高我们的app的运行效果和体验
但是有时候也容易引发一些问题
比如资源的抢占问题 多个线程同时访问同一个对象 同一个文件或者变量

先简单介绍一下自旋锁和互斥锁
自旋锁是高级锁 不会进入休眠 会一直在那里等待 处于忙等状态
互斥锁在等待的时候会进入休眠 然后等待唤醒
不过进入睡眠和醒来都是会消耗性能的
什么情况使用自旋锁比较划算?
预计等待锁的时间比较短
加锁的代码区块经常被调用,但竞争情况很少发生
CPU资源不紧张
多核处理器
什么情况使用互斥锁比较划算?
预计线程等待时间比较长
单核处理器
临界区有IO操作
临界区代码复杂或者循环量大
临界区竞争非常激烈
@synchronized
创建单例的时候使用
OSSpinLock
OSSpinLock是自旋锁
首先这个锁的效率是很高的 基本在所有的锁里面最高的 但是因为这个锁现在已经不安全了 原因如下
如果一个低优先级的线程获得锁并访问共享资源,这时一个高优先级的线程也尝试获得这个锁,它会处于 spin lock 的忙等状态从而占用大量 CPU。此时低优先级线程无法与高优先级线程争夺 CPU 时间,从而导致任务迟迟完不成、无法释放 lock
简而言之 就是OSSpinLock有潜在的优先级反转问题
以上就是出现优先级反转的场景 需要注意,那么怎么预防呢?
当优先级低的任务进来的时候 这时候要是有高优先级的任务等待中 那么只需要提升这个优先级低的任务 让他高于这个高优先级的 等执行完之后 再恢复到原来的优先级,当然这个优先级高的线程为什么一直在这等着 这需要注意 是否必要,总之要使临界区的锁时间尽可能的短
os_unfair_lock
从ios10开始 苹果官方推荐使用 os_unfair_lock
这个锁的效率也是极高的
官方文档里面有对os_unfair_lock的描述是low level lock 它会在等待的时候进入休眠状态 而互斥锁的特点就是在等待的时候会进入休眠 所以我们也可以把os_unfair_lock看做是互斥锁 用来代替NSSpinLock的
pthread_mutex
pthread_mutex 是c底层的线程锁 (是一个跨平台的锁)
pthread_mutex 会初始化一个条件 决定它是自旋锁还是互斥锁
因为是C语言函数 所以系统不会自动销毁 用完之后需要手动销毁
NS系列锁
NS系列锁指的是NSLock、NSCondition、NSConditionLock、NSRecursiveLock,之所以把这几个放在一起,是因为它们都遵守NSLocking协议,就俩方法,加锁解锁,so easy!
@protocol NSLocking
- (void)lock;
- (void)unlock;
@end这里补充一下上锁的两种方式trylock和lock使用场景:
当前线程锁失败,也可以继续其它任务,用 trylock 合适
当前线程只有锁成功后,才会做一些有意义的工作,那就 lock,没必要轮询 trylock
lockBeforeDate:这个方法表示会在传入的时间内尝试加锁,若能加锁则执行加锁操作并返回 YES,反之返回 NO。
NSLock线程锁
NSCondition 条件锁
NSRecursiveLock是对 递归锁的封装
NSConditionLock 是对pthread_mutex 和conditon条件的封装
@synchronized 性能是最差的
知识小结
所有的锁基本都是创建锁、加锁、等待、解锁的流程,所以并不复杂。
如果追求锁的极致性能,可以考虑更偏底层实现的pthread_mutex互斥锁以及信号量的方式。
@synchronized的效率最低,但是它使用最方便,所以如果没有性能瓶颈的话使用它也不错。