iOS 底层探索篇 —— 八大锁的分析
1. 锁的类型
自旋锁
:线程反复检查锁变量是否可用。由于线程在这一过程中保持执行, 因此是一种忙等待
。一旦获取了自旋锁,线程会一直保持该锁
,直至显式释放自旋锁。 自旋锁避免了进程上下文的调度开销
,因此对于线程只会阻塞很短时间
的场合是有效的。
互斥锁
:是一种用于多线程编程中,防止两条线程同时对同一公共资源(比 如全局变量)进行读写的机制有互斥和同步两个特点。当一个线程在进行任务的时候,别的线程就不能进行这个任务,这就是互斥。别的线程按照一定的顺序在这个线程完成后执行,这就是同步。该目的通过将代码切片成一个一个的临界区
而达成,互斥锁分为递归锁和非递归锁。这里属于互斥锁的有:
- NSLock
- pthread_mutex
- @synchronized
条件锁
:就是条件变量,当进程的某些资源要求不满足
时就进入休眠
,也就是锁住了。当资源被分配到
了,条件锁打开
,进程继续运行
- NSCondition
- NSConditionLock
递归锁
:就是同一个线程可以加锁N次
而不会引发死锁
- NSRecursiveLock
- pthread_mutex(recursive)
信号量(semaphore):
是一种更高级的同步机制,互斥锁可以说是 semaphore 在仅取值0/1时的特例
。信号量可以有更多的取值空间,用来实现更加复杂的同步,而不单单是线程间互斥。
- dispatch_semaphore
其实基本的锁就包括了三类 自旋锁
互斥锁
读写锁
,
其他的比如条件锁,递归锁,信号量都是上层的封装和实现
!
2. 锁的应用
这里的代码运行后会奔溃,崩溃的主要原因是testArray在某一瞬间变成了nil。
下面这段代码如果执行的话,就会有10个testMethod(10)在异步执行,那么如何确保他们一个接一个执行呢?也就是应该怎么加锁呢?
这里把锁加在testMethod(10)前后就解决了问题,这里也可以在testMethod声明之后加锁。这里不能在testMethod的代码块里面加锁,否则就会递归加锁,而NSLock不支持递归加锁。
那么如果加了递归锁,是否可以这样加锁呢?答案也是不行的,因为这里面是多线程环境,递归锁无法进行多线程可递归。而要多线程,可递归,则需要用@synchronized锁。
这里看到加了@synchronized锁之后是正常运行的。