鎖的作用:保證線程安全。
鎖的分類:互斥鎖,自旋鎖,其它比如條件鎖,遞歸鎖,信號(hào)量都是上層的封裝和實(shí)現(xiàn)。
互斥鎖
防止兩條線程同時(shí)對(duì)同一公共資源進(jìn)行讀寫的機(jī)制。當(dāng)獲取鎖操作失敗時(shí),線程會(huì)進(jìn)入睡眠,等待鎖釋放時(shí)被喚醒。
互斥鎖分為:
- 遞歸鎖:可重入鎖,同一個(gè)線程在鎖釋放前可再次獲取鎖,可以遞歸調(diào)用
- 非遞歸鎖:不可重入,必須等鎖釋放后才能再次獲取鎖。
自旋鎖
線程反復(fù)檢查鎖變量是否可用。由于線程在這一過程中保持執(zhí)行,因此是一種忙等待。一旦獲取自旋鎖,線程會(huì)一直保持該鎖,直到顯式釋放。
優(yōu)點(diǎn):避免了線程的上下文調(diào)度開銷,因此對(duì)于線程只會(huì)阻塞很短時(shí)間的場(chǎng)景很有用。
互斥鎖和自旋鎖區(qū)別
- 互斥鎖在線程沒獲取到鎖時(shí),線程會(huì)進(jìn)入休眠狀態(tài),等鎖被釋放時(shí)會(huì)被喚醒
- 自旋鎖的線程會(huì)一直處于等待(忙等待),不會(huì)進(jìn)入休眠,效率高。
自旋鎖種類
1. OSSpinLock
自旋鎖存在不安全機(jī)制,因?yàn)樽孕i會(huì)讓線程處于忙等待,因此高優(yōu)先級(jí)的線程可能一直占用CPU,造成低優(yōu)先級(jí)的任務(wù)無法執(zhí)行,不能釋放鎖。
2. 讀寫鎖
- 寫是排他的,同時(shí)只能有一個(gè)寫或者多個(gè)讀,但不能同時(shí)讀寫。
- 若當(dāng)前沒有讀寫,寫可以立即獲得讀寫鎖,否則必須等待沒有任何讀寫者。如果沒有寫,讀可以立即獲得鎖,否則不謝等寫釋放鎖。
互斥鎖
pthread_mutex
全局聲明
#import <pthread.h>
pthread_mutex_t _lock;
- (void)addCount {
pthread_mutex_lock(&_lock);
for (int i = 0; i < 10; i++) {
self.count += 1;
NSLog(@"----- %d", self.count);
}
pthread_mutex_unlock(&_lock);
}
- (void)method1 {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self addCount];
});
}
- (void)method2 {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self addCount];
});
}
@synchronized
@synchronized (self) {
for (int i = 0; i < 10; i++) {
self.count += 1;
NSLog(@"----- %d", self.count);
}
}
- 不能使用非OC對(duì)象作為加鎖條件——id2data中接收參數(shù)為id類型
- 多次鎖同一個(gè)對(duì)象會(huì)有什么后果嗎——會(huì)從高速緩存中拿到data,所以只會(huì)鎖一次對(duì)象
- 都說@synchronized性能低——是因?yàn)樵诘讓釉鰟h改查消耗了大量性能
- 加鎖對(duì)象不能為nil,否則加鎖無效,不能保證線程安全
NSLock
是對(duì)互斥鎖的簡(jiǎn)單封裝
[self.lock lock];
//[self.lock lock] 重復(fù)兩次會(huì)造成線程永久鎖死
for (int i = 0; i < 10; i++) {
self.count += 1;
NSLog(@"----- %d", self.count);
}
[self.lock unlock];
NSLock在解鎖前不能重復(fù)加鎖。
NSRecursiveLock
可重復(fù)加鎖
dispatch_semaphore
NSCondition
NSConditionLock
性能對(duì)比

性能對(duì)比.png
參考:https://juejin.im/post/5ec9f3ec6fb9a047f0125fd2#heading-32