synchronized
@synchronized(obj)指令使用的obj為該鎖的唯一標識,只有當標識相同時抛虏,才為滿足互斥匿辩,如果線程2中的@synchronized(obj)改為@synchronized(self),剛線程2就不會被阻塞。
@synchronized指令實現(xiàn)鎖的優(yōu)點就是我們不需要在代碼中顯式的創(chuàng)建鎖對象富稻,便可以實現(xiàn)鎖的機制栅盲,但作為一種預防措施汪诉,@synchronized塊會隱式的添加一個異常處理例程來保護代碼,該處理例程會在異常拋出的時候自動的釋放互斥鎖。所以如果不想讓隱式的異常處理例程帶來額外的開銷扒寄,你可以考慮使用鎖對象鱼鼓。
-
(void)synchronizedLock {
NSObject * obj = NSObject.alloc.init;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
@synchronized(obj) {
NSLog(@"需要線程同步的操作1 開始");
sleep(3);
NSLog(@"需要線程同步的操作1 結(jié)束");
}
});dispatch_async(dispatch_get_global_queue(0, 0), ^{
sleep(1);
@synchronized(obj) {
NSLog(@"需要線程同步的操作2");
}
});/**
需要線程同步的操作1 開始
需要線程同步的操作1 結(jié)束
需要線程同步的操作2
*/
}
NSLock
NSLock是Cocoa提供給我們最基本的鎖對象,這也是我們經(jīng)常所使用的该编,除lock和unlock方法外迄本,NSLock還提供了tryLock和lockBeforeDate:兩個方法,前一個方法會嘗試加鎖课竣,如果鎖不可用(已經(jīng)被鎖住)嘉赎,剛并不會阻塞線程,并返回NO于樟。lockBeforeDate:方法會在所指定Date之前嘗試加鎖曹阔,如果在指定時間之前都不能加鎖,則返回NO隔披。
-
(void)nslockLock {
NSLock * lock = NSLock.alloc.init;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// [lock lock];
[lock lockBeforeDate:NSDate.date];
NSLog(@"需要線程同步的操作1 開始");
sleep(2);
NSLog(@"需要線程同步的操作1 結(jié)束");
[lock unlock];
});dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
if (lock.tryLock) { //嘗試獲取鎖赃份,如果獲取不到返回NO,不會阻塞
NSLog(@"未上鎖");
[lock unlock];
}else {
NSLog(@"已被上鎖");
}NSDate *date = [NSDate.alloc initWithTimeIntervalSinceNow:3]; if ([lock lockBeforeDate:date]) { NSLog(@"沒有超時,獲得鎖"); [lock unlock]; } else { NSLog(@"超時奢米,沒有獲得鎖"); }
});
/**
需要線程同步的操作1 開始
已被上鎖
需要線程同步的操作1 結(jié)束
沒有超時抓韩,獲得鎖
*/
}
semaphore
如果dsema信號量的值大于0,該函數(shù)所處線程就繼續(xù)執(zhí)行下面的語句鬓长,并且將信號量的值減1谒拴;如果desema的值為0,那么這個函數(shù)就阻塞當前線程等待timeout(注意timeout的類型為dispatch_time_t涉波,不能直接傳入整形或float型數(shù))英上,如果等待的期間desema的值被dispatch_semaphore_signal函數(shù)加1了,且該函數(shù)(即dispatch_semaphore_wait)所處線程獲得了信號量啤覆,那么就繼續(xù)向下執(zhí)行并將信號量減1苍日。如果等待期間沒有獲取到信號量或者信號量的值一直為0,那么等到timeout時窗声,其所處線程自動執(zhí)行其后語句相恃。
dispatch_semaphore 是信號量,但當信號總量設(shè)為 1 時也可以當作鎖來笨觅。在沒有等待情況出現(xiàn)時拦耐,它的性能比 pthread_mutex還要高,但一旦有等待情況出現(xiàn)時见剩,性能就會下降許多杀糯。相對于 OSSpinLock 來說,它的優(yōu)勢在于等待時不會消耗 CPU 資源苍苞。
-
(void)semaphoreLock {
dispatch_semaphore_t signal = dispatch_semaphore_create(1); //初始信號量為1
dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC); //鎖幾秒dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_semaphore_wait(signal, overTime); //信號量減1
NSLog(@"需要線程同步的操作1 開始");
sleep(2);
NSLog(@"需要線程同步的操作1 結(jié)束");
dispatch_semaphore_signal(signal); //信號量加1
});dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
dispatch_semaphore_wait(signal, overTime);
dispatch_semaphore_signal(signal);
});/**
需要線程同步的操作1 開始
需要線程同步的操作1 結(jié)束
需要線程同步的操作2如果超時時間overTime設(shè)置成>2固翰,可完成同步操作。如果overTime<2的話,在線程1還沒有執(zhí)行完成的情況下倦挂,此時超時了,將自動執(zhí)行下面的代碼担巩。
需要線程同步的操作1 開始
需要線程同步的操作2
需要線程同步的操作1 結(jié)束
*/
}
NSRecursiveLock 遞歸鎖
NSRecursiveLock是一個遞歸鎖方援,這個鎖可以被同一線程多次請求,而不會引起死鎖涛癌。這主要是用在循環(huán)或遞歸操作中犯戏。
這段代碼是一個典型的死鎖情況。在我們的線程中拳话,RecursiveMethod是遞歸調(diào)用的先匪。所以每次進入這個block時,都會去加一次鎖弃衍,而從第二次開始呀非,由于鎖已經(jīng)被使用了且沒有解鎖,所以它需要等待鎖被解除镜盯,這樣就導致了死鎖岸裙,線程被阻塞住了。
使用NSRecursiveLock速缆。它可以允許同一線程多次加鎖降允,而不會造成死鎖。遞歸鎖會跟蹤它被lock的次數(shù)艺糜。每次成功的lock都必須平衡調(diào)用unlock操作剧董。只有所有達到這種平衡,鎖最后才能被釋放破停,以供其它線程使用翅楼。
-
(void)recursiveLock {
// NSLock * lock = NSLock.alloc.init; //使用nslock會產(chǎn)生死鎖
NSRecursiveLock * lock = NSRecursiveLock.alloc.init;dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
static void (^RecursiveMethod)(int);RecursiveMethod = ^(int value) { [lock lock]; if (value > 0) { NSLog(@"value = %@",@(value)); sleep(1); RecursiveMethod(value - 1); } [lock unlock]; }; RecursiveMethod(6);
});
/**
value = 6
value = 5
value = 4
value = 3
value = 2
value = 1
*/
}
NSConditionLock 條件鎖
- (void)lockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition;
這兩個condition一樣的時候會相互通知。
初始化 self.condition = [[NSConditionLock alloc]initWithCondition:0];
獲得鎖 [self.condition lockWhenCondition:1];
解鎖 [self.condition unlockWithCondition:1];
-
(void)conditionLockLock {
NSConditionLock * lock = [NSConditionLock.alloc initWithCondition:0];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (YES) {
[lock lockWhenCondition:1];
NSLog(@"需要線程同步的操作1 開始");
sleep(2);
NSLog(@"需要線程同步的操作1 結(jié)束");
[lock unlockWithCondition:0];
}
});dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (YES) {
[lock lockWhenCondition:0];
NSLog(@"需要線程同步的操作2 開始");
sleep(1);
NSLog(@"需要線程同步的操作2 結(jié)束");
[lock unlockWithCondition:2];
}
});dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (YES) {
[lock lockWhenCondition:2];
NSLog(@"需要線程同步的操作3 開始");
sleep(1);
NSLog(@"需要線程同步的操作3 結(jié)束");
[lock unlockWithCondition:1];
}
});/**
需要線程同步的操作2 開始
需要線程同步的操作2 結(jié)束
需要線程同步的操作3 開始
需要線程同步的操作3 結(jié)束
需要線程同步的操作1 開始
需要線程同步的操作1 結(jié)束
*/
}
NSContidion
一種最基本的條件鎖真慢。手動控制線程wait和signal犁嗅。
[condition lock];一般用于多線程同時訪問、修改同一個數(shù)據(jù)源晤碘,保證在同一時間內(nèi)數(shù)據(jù)源只被訪問褂微、修改一次,其他線程的命令需要在lock 外等待园爷,只到unlock 宠蚂,才可訪問
[condition unlock];與lock 同時使用
[condition wait];讓當前線程處于等待狀態(tài)
[condition signal];CPU發(fā)信號告訴線程不用在等待,可以繼續(xù)執(zhí)行
-
(void)contidionLock {
NSCondition * condition = NSCondition.alloc.init;
NSMutableArray * products = NSMutableArray.array;dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (YES) {
[condition lock];
if (products.count == 0) {
NSLog(@"wait for product");
[condition wait];
}
[products removeObjectAtIndex:0];
NSLog(@"custome a product");
[condition unlock];
}
});dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (YES) {
[condition lock];
[products addObject:NSObject.alloc.init];
NSLog(@"produce a product童社,總量:%ld",products.count);
[condition signal];
[condition unlock];
sleep(2);
}
});/**
wait for product
produce a product求厕,總量:1
custome a productwait for product
produce a product,總量:1
custome a product
*/
}#pthread_mutex
c語言定義下多線程加鎖方式。
pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t attr);
初始化鎖變量mutex呀癣。attr為鎖屬性美浦,NULL值為默認屬性。
pthread_mutex_lock(pthread_mutex_t mutex);加鎖
pthread_mutex_tylock(pthread_mutex_t mutex);加鎖项栏,但是與2不一樣的是當鎖已經(jīng)在使用的時候浦辨,返回為EBUSY,而不是掛起等待沼沈。
pthread_mutex_unlock(pthread_mutex_t mutex);*釋放鎖
pthread_mutex_destroy(pthread_mutex_t mutex);使用完后釋放
-
(void)pthread_mutexLock {
__block pthread_mutex_t theLock ;
pthread_mutex_init(&theLock, NULL);dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
pthread_mutex_lock(&theLock);
NSLog(@"需要線程同步的操作1 開始");
sleep(3);
NSLog(@"需要線程同步的操作1 結(jié)束");
pthread_mutex_unlock(&theLock);});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
pthread_mutex_lock(&theLock);
NSLog(@"需要線程同步的操作2");
pthread_mutex_unlock(&theLock);
});/**
需要線程同步的操作1 開始
需要線程同步的操作1 結(jié)束
需要線程同步的操作2
*/
}
pthread_mutex(recursive) 遞歸鎖
這是pthread_mutex為了防止在遞歸的情況下出現(xiàn)死鎖而出現(xiàn)的遞歸鎖流酬。作用和NSRecursiveLock遞歸鎖類似。
如果使用pthread_mutex_init(&theLock, NULL);初始化鎖的話列另,上面的代碼會出現(xiàn)死鎖現(xiàn)象芽腾。如果使用遞歸鎖的形式,則沒有問題页衙。
PTHREAD_MUTEX_NORMAL 缺省類型摊滔,也就是普通鎖。當一個線程加鎖以后店乐,其余請求鎖的線程將形成一個等待隊列惭载,并在解鎖后先進先出原則獲得鎖。
PTHREAD_MUTEX_ERRORCHECK 檢錯鎖响巢,如果同一個線程請求同一個鎖描滔,則返回 EDEADLK,否則與普通鎖類型動作相同踪古。這樣就保證當不允許多次加鎖時不會出現(xiàn)嵌套情況下的死鎖含长。
PTHREAD_MUTEX_RECURSIVE 遞歸鎖,允許同一個線程對同一個鎖成功獲得多次伏穆,并通過多次 unlock 解鎖拘泞。
PTHREAD_MUTEX_DEFAULT 適應鎖,動作最簡單的鎖類型枕扫,僅等待解鎖后重新競爭陪腌,沒有等待隊列。
-
(void)pthread_mutexrecursiveLock {
__block pthread_mutex_t theLock;pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); //設(shè)置type未遞歸
pthread_mutex_init(&theLock, &attr);
pthread_mutexattr_destroy(&attr);dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
static void (^RecursiveMethod)(int);RecursiveMethod = ^(int value) { pthread_mutex_lock(&theLock); if (value > 0) { NSLog(@"value = %@",@(value)); sleep(1); RecursiveMethod(value - 1); } pthread_mutex_unlock(&theLock); }; RecursiveMethod(5);
});
/**
value = 5
value = 4
value = 3
value = 2
value = 1
*/
}
OSSpinLock OSSpinLock 自旋鎖烟瞧,性能最高的鎖诗鸭。原理很簡單,就是一直 do while 忙等参滴。它的缺點是當?shù)却龝r會消耗大量 CPU 資源强岸,所以它不適用于較長時間的任務(wù)。 不過最近YY大神在自己的博客不再安全的 OSSpinLock中說明了OSSpinLock已經(jīng)不再安全砾赔,請大家謹慎使用蝌箍。 青灼。
-
(void)osspinLock {
_block OSSpinLock theLock = OS_SPINLOCK_INIT;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
OSSpinLockLock(&theLock);
NSLog(@"需要線程同步的操作1 開始");
sleep(3);
NSLog(@"需要線程同步的操作1 結(jié)束");
OSSpinLockUnlock(&theLock);});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
OSSpinLockLock(&theLock);
sleep(1);
NSLog(@"需要線程同步的操作2");
OSSpinLockUnlock(&theLock);});
}
效率對比如下:
l
來源:本文來自第三方轉(zhuǎn)載,如有侵權(quán)請聯(lián)系小編刪除妓盲。
給大家推薦一個iOS技術(shù)交流群杂拨,群內(nèi)提供數(shù)據(jù)結(jié)構(gòu)與算法、底層進階悯衬、swift弹沽、逆向、底層面試題整合文檔等免費資料I跬ぁ4摇击胜!
可加我QQ3140276761邀請大家進群亏狰。