-
為什么用鎖:
多線程編程中知纷,如果對同一數(shù)據(jù)源進行讀寫操作就會造成不可預知的結(jié)果,所以我們應(yīng)該盡量避免并發(fā)操作資源在線程之間共享是辕,以減少線程間的相互作用眉反,就需要一些同步工具狞谱,來確保當它們交互的時候是安全的。
-
鎖的種類:
iOS開發(fā)中常用的鎖有如下幾種:
- @synchronized 同步鎖
- NSLock 對象鎖
- NSRecursiveLock 遞歸鎖
- NSConditionLock 條件鎖
- pthread_mutex 互斥鎖(C語言)
- dispatch_semaphore 信號量實現(xiàn)加鎖(GCD)
- OSSpinLock 自旋鎖 (暫不建議使用禁漓,原因參見這里)
-
鎖的性能對比:
我們先來看一下網(wǎng)上的評測跟衅,幾乎關(guān)于鎖性能介紹的文章都用了這張圖:那根據(jù)這張圖所描述的耗時對別正確嗎?我們自己實際測試一下播歼,看下邊的測試代碼:
#import <pthread.h> #import <libkern/OSAtomic.h> #define CycleTime (1024*1024*32) - (void)testAction { NSTimeInterval time = [NSDate date].timeIntervalSince1970; //同步鎖 for (int i = 0; i < CycleTime; i++) { @synchronized(self) { } } NSLog(@"%f : work time of Synchronized",[NSDate date].timeIntervalSince1970-time); time = [NSDate date].timeIntervalSince1970; //條件鎖 NSConditionLock *conditionLock = [[NSConditionLock alloc] init]; for (int i = 0; i < CycleTime; i++) { [conditionLock lock]; [conditionLock unlock]; } NSLog(@"%f : work time of NSConditionLock",[NSDate date].timeIntervalSince1970-time); time = [NSDate date].timeIntervalSince1970; //遞歸鎖 NSRecursiveLock *rsLock = [[NSRecursiveLock alloc] init]; for (int i = 0; i < CycleTime; i++) { [rsLock lock]; [rsLock unlock]; } NSLog(@"%f : work time of NSRecursiveLock",[NSDate date].timeIntervalSince1970-time); time = [NSDate date].timeIntervalSince1970; //互斥鎖 NSLock *mutexLock = [[NSLock alloc] init]; for (int i = 0; i < CycleTime; i++) { [mutexLock lock]; [mutexLock unlock]; } NSLog(@"%f : work time of NSLock",[NSDate date].timeIntervalSince1970-time); time = [NSDate date].timeIntervalSince1970; //互斥鎖 pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); for (int i = 0; i < CycleTime; i++) { pthread_mutex_lock(&mutex); pthread_mutex_unlock(&mutex); } NSLog(@"%f : work time of pthread_mutex",[NSDate date].timeIntervalSince1970-time); time = [NSDate date].timeIntervalSince1970; //信號量 dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); for (int i = 0; i < CycleTime; i++) { dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_semaphore_signal(semaphore); } NSLog(@"%f : work time of dispatch_semaphore",[NSDate date].timeIntervalSince1970-time); time = [NSDate date].timeIntervalSince1970; //自旋鎖 OSSpinLock spinlock = OS_SPINLOCK_INIT; for (int i = 0; i < CycleTime; i++) { OSSpinLockLock(&spinlock); OSSpinLockUnlock(&spinlock); } NSLog(@"%f : work time of OSSpinLock",[NSDate date].timeIntervalSince1970-time); }
輸出:
2018-03-29 18:51:14.638390+0800 Lock[97416:4313533] 3.498765 : work time of Synchronized 2018-03-29 18:51:16.987938+0800 Lock[97416:4313533] 2.349282 : work time of NSConditionLock 2018-03-29 18:51:18.480868+0800 Lock[97416:4313533] 1.492687 : work time of NSRecursiveLock 2018-03-29 18:51:19.286578+0800 Lock[97416:4313533] 0.805475 : work time of NSLock 2018-03-29 18:51:20.029690+0800 Lock[97416:4313533] 0.742872 : work time of pthread_mutex 2018-03-29 18:51:20.556899+0800 Lock[97416:4313533] 0.526966 : work time of dispatch_semaphore 2018-03-29 18:51:20.909306+0800 Lock[97416:4313533] 0.352188 : work time of OSSpinLock
看輸出結(jié)果一目了然了伶跷,跟上圖的評測結(jié)果一致掰读。
-
如何使用鎖:
- @synchronized賣票例子:
- (void)sycnAction { __block int ticketsCount = 5; void(^saleTickets)(void) = ^() { while (YES) { /* 注意點: 1.加鎖的代碼盡量少 2.添加的OC對象必須在多個線程中都是同一對象 3.優(yōu)點是不需要顯式的創(chuàng)建鎖對象,便可以實現(xiàn)鎖的機制叭莫。 4.@synchronized塊會隱式的添加一個異常處理例程來保護代碼蹈集,該處理例程會在異常拋出的時候自動的釋放互斥鎖雇初。所以如果不想讓隱式的異常處理例程帶來額外的開銷,你可以考慮使用鎖對象靖诗。 */ //這里參數(shù)添加一個OC對象,一般使用self @synchronized(self) { [NSThread sleepForTimeInterval:1]; if (ticketsCount > 0) { ticketsCount--; NSLog(@"Tickets = %d, Thread:%@",ticketsCount,[NSThread currentThread]); } else { NSLog(@"Clear Thread:%@",[NSThread currentThread]); break; } } } }; NSLog(@"Start tickets count = %d, Thread:%@",ticketsCount,[NSThread currentThread]); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ saleTickets(); }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ saleTickets(); }); }
- NSLock互斥鎖賣票例子:
- (void)lockAction { __block int ticketsCount = 5; NSLock *lock = [[NSLock alloc] init]; void(^lockSaleTickets)(void) = ^() { while (1) { [lock lock]; [NSThread sleepForTimeInterval:1]; if (ticketsCount > 0) { ticketsCount--; NSLog(@"Tickets= %d, Thread:%@",ticketsCount,[NSThread currentThread]); } else { NSLog(@"Clear Thread:%@",[NSThread currentThread]); break; } [lock unlock]; } }; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ lockSaleTickets(); }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ lockSaleTickets(); }); }
- NSRecursiveLock遞歸鎖賣票例子:
- (void)recursiveLockAction { // NSLock *lock = [[NSLock alloc] init]; NSRecursiveLock *lock = [[NSRecursiveLock alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ static void(^TestMethod)(int); TestMethod = ^(int value) { [lock lock]; if (value > 0) { NSLog(@"value = %d",value); [NSThread sleepForTimeInterval:1]; TestMethod(--value); } [lock unlock]; }; NSLog(@"Begain Test"); TestMethod(5); }); }
- NSConditionLock條件鎖賣票例子:
- (void)conditionLockActive { NSConditionLock *lock = [[NSConditionLock alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for (int i = 0; i <= 5; i++) { [lock lock]; NSLog(@"1.thread1 condition = %ld, i = %d",(long)lock.condition,i); [lock unlockWithCondition:i]; NSLog(@"2.thread1 condition = %ld, i = %d",(long)lock.condition,i); } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ [lock lockWhenCondition:2]; NSLog(@"thread2"); [lock unlock]; }); }
- pthread_mutex_t互斥鎖例子:
- (void)pthreadMutexAction { __block pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(2); pthread_mutex_lock(&mutex); NSLog(@"任務(wù)2"); pthread_mutex_unlock(&mutex); }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ pthread_mutex_lock(&mutex); NSLog(@"任務(wù)1"); pthread_mutex_unlock(&mutex); }); }
- dispatch_semaphore_t信號量例子:
- (void)semaphoreAction { dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); __block int count = 10; void(^TestMethod)(void) = ^() { while (YES) { dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); if (count > 0) { count --; NSLog(@"value = %d, %@",count,[NSThread currentThread]); [NSThread sleepForTimeInterval:1]; } else { NSLog(@"Done %@",[NSThread currentThread]); break; } dispatch_semaphore_signal(semaphore); } }; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ TestMethod(); }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ TestMethod(); }); }
- OSSpinLock自旋鎖例子:
- (void)spinAction { __block int tickets = 5; OSSpinLock spinlock = OS_SPINLOCK_INIT; void(^TestMethod)(void) = ^() { while (YES) { OSSpinLockLock(&spinlock); if (tickets > 0) { tickets --; NSLog(@"value = %d, %@",tickets,[NSThread currentThread]); [NSThread sleepForTimeInterval:1]; } else { NSLog(@"Done %@",[NSThread currentThread]); break; } OSSpinLockUnlock(&spinlock); } }; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ TestMethod(); }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ TestMethod(); }); }
-
死鎖:待續(xù)....
iOS多線程(6)-Lock
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進店門贮缕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人俺榆,你說我怎么就攤上這事感昼。” “怎么了罐脊?”我有些...
- 文/不壞的土叔 我叫張陵定嗓,是天一觀的道長。 經(jīng)常有香客問我萍桌,道長宵溅,這世上最難降的妖魔是什么? 我笑而不...
- 正文 為了忘掉前任上炎,我火速辦了婚禮恃逻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己寇损,他們只是感情好凸郑,可當我...
- 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著矛市,像睡著了一般芙沥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上浊吏,一...
- 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼底桂!你這毒婦竟也來了植袍?” 一聲冷哼從身側(cè)響起,我...
- 正文 年R本政府宣布,位于F島的核電站粒没,受9級特大地震影響簇爆,放射性物質(zhì)發(fā)生泄漏倾贰。R本人自食惡果不足惜匆浙,卻給世界環(huán)境...
- 文/蒙蒙 一首尼、第九天 我趴在偏房一處隱蔽的房頂上張望言秸。 院中可真熱鬧,春花似錦举畸、人聲如沸。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至率挣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間椒功,已是汗流浹背。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- iOS多線程實踐中竭钝,常用的就是子線程執(zhí)行耗時操作,然后回到主線程刷新UI香罐。在iOS中每個進程啟動后都會建立一個主線...
- 轉(zhuǎn)載自:http://www.reibang.com/p/938d68ed832c# 一庇茫、前言 前段時間看了幾個...
- 前言 各路大神對GCD的原理解析和使用方法網(wǎng)上到處都是,可以輕松搜索到。那為什么筆者還要自己動手寫一篇所謂的"葵花...