由于之前開發(fā)中用到了鎖這個(gè)東西蠕趁,加上這個(gè)知識(shí)在之前的項(xiàng)目中用之甚少懦底,所以對(duì)于此想做一下在百度網(wǎng)上文章過程中的再一次了解中的簡(jiǎn)單總結(jié)雅任。
基本思路就三點(diǎn):1:iOS中有幾種常用的鎖
2:幾種鎖的性能及個(gè)別鎖的簡(jiǎn)單使用
3:對(duì)于常用鎖中互斥鎖(NSLock 和@synchronized)和自旋鎖的區(qū)別
首先要知道鎖是一種同步機(jī)制懈息,用于在存在多線程環(huán)境中實(shí)施對(duì)資源訪問限制肾档。其中有互斥鎖、對(duì)象所辫继、遞歸鎖怒见、條件鎖、自旋鎖姑宽、信號(hào)量實(shí)現(xiàn)加鎖這幾種遣耍。他們分別有自己的處理機(jī)制故而性能也不盡相同,具體性能由快到慢簡(jiǎn)單總結(jié)如下:
OSSpinLock(性能最高但不再安全 具體使用方式也無須過于了解炮车,iOS SDK里無OSSpinLock頭文件可導(dǎo) 用不了)>
dispatch_semaphore (信號(hào)量加鎖)> pthread_mutex (互斥鎖)> NSLock (對(duì)象鎖 也是互斥鎖的一種)>NSRecursiveLock (遞歸鎖) >NSConditionLock (條件鎖)> @synchronized (互斥鎖)
以下列舉簡(jiǎn)單使用的買票實(shí)例 http://www.reibang.com/p/1e59f0970bf5 (從此文章中粘入幾個(gè)實(shí)例引用便于自己觀看回顧)
@synchronized 是一個(gè) OC 層面的鎖舵变, 主要是通過犧牲性能換來語法上的簡(jiǎn)潔,@synchronized 后面需要緊跟一個(gè) OC 對(duì)象瘦穆,它實(shí)際上是把這個(gè)對(duì)象當(dāng)做鎖來使用纪隙。這是通過一個(gè)哈希表來實(shí)現(xiàn)的,OC 在底層使用了一個(gè)互斥鎖的數(shù)組(你可以理解為鎖池)扛或,通過對(duì)對(duì)象去哈希值來得到對(duì)應(yīng)的互斥鎖绵咱。
//設(shè)置票的數(shù)量為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(@"剩余票數(shù)= %ld, Thread:%@",_tickets,[NSThread currentThread]);
} else {
NSLog(@"票賣完了 Thread:%@",[NSThread currentThread]);
break;
}
}
}
}
NSLock 互斥鎖只是在內(nèi)部封裝了一個(gè) pthread_mutex,屬性為PTHREAD_MUTEX_ERRORCHECK熙兔,它會(huì)損失一定性能換來錯(cuò)誤提示悲伶。不能多次調(diào)用lock
//設(shè)置票的數(shù)量為5
_tickets = 5;
//創(chuàng)建鎖
_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(@"剩余票數(shù)= %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 (遞歸鎖)
//創(chuàng)建鎖
_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 互斥鎖 需要導(dǎo)入#include <pthread.h>
__block pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
//線程1
dispatch_async(self.concurrentQueue), ^{
pthread_mutex_lock(&mutex);
NSLog(@"任務(wù)1");
sleep(2);
pthread_mutex_unlock(&mutex);
});
//線程2
dispatch_async(self.concurrentQueue), ^{
sleep(1);
pthread_mutex_lock(&mutex);
NSLog(@"任務(wù)2");
pthread_mutex_unlock(&mutex);
});
dispatch_semaphore 信號(hào)量實(shí)現(xiàn)加鎖
// 創(chuàng)建信號(hào)量
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(@"任務(wù)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(@"任務(wù)2");
dispatch_semaphore_signal(semaphore);
});
自旋鎖
bool lock = false; // 一開始沒有鎖上,任何線程都可以申請(qǐng)鎖
do {
while(test_and_set(&lock); // test_and_set 是一個(gè)原子操作
Critical section // 臨界區(qū)
lock = false; // 相當(dāng)于釋放鎖黔姜,這樣別的線程可以進(jìn)入臨界區(qū)
Reminder section // 不需要鎖保護(hù)的代碼
}
對(duì)于自旋鎖和互斥鎖二者的區(qū)別
相同點(diǎn)在于:都能保證同一時(shí)間只有一個(gè)線程訪問共享資源 保證安全
不同點(diǎn)在于:1自旋鎖效率高于互斥鎖
2如果共享數(shù)據(jù)已有其他線程加鎖了拢切,互斥鎖會(huì)使線程進(jìn)入休眠狀態(tài)等待解鎖,如果資源解鎖秆吵,則線程被喚醒淮椰。而自旋鎖會(huì)使線程以死循環(huán)的方式等待解鎖,如果資源解鎖,則另一個(gè)線程會(huì)立即執(zhí)行
PS:atomic內(nèi)部為互斥鎖 ->其中setter方法中多了個(gè)@synchronized(self){} <-等當(dāng)前對(duì)象操作完畢會(huì)合成確定值