為什么需要使用鎖凌彬,當然熟悉多線程的你,自然不會對它覺得陌生。
那你在代碼中是否很好的使用了鎖的機制呢践惑?你又知道幾種實現(xiàn)鎖的方法呢?
今天一起來探討一下Objective-C中幾種不同方式實現(xiàn)的鎖嘶卧,在這之前我們先構建一個測試用的類尔觉,假想它是我們的一個共享資源,method1與method2是互斥的芥吟,代碼如下:
@implementationTestObj
- (void)method1
{
NSLog(@"%@",NSStringFromSelector(_cmd));
}
- (void)method2
{
NSLog(@"%@",NSStringFromSelector(_cmd));
}
@end
1.使用NSLock實現(xiàn)的鎖
//主線程中
TestObj *obj = [[TestObj alloc] init];
NSLock*lock = [[NSLockalloc] init];
//線程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
[lock lock];
[obj method1];
sleep(10);
[lock unlock];
});
//線程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
sleep(1);//以保證讓線程2的代碼后執(zhí)行
[lock lock];
[obj method2];
[lock unlock];
});
看到打印的結果了嗎侦铜,你會看到線程1鎖住之后,線程2會一直等待走到線程1將鎖置為unlock后钟鸵,才會執(zhí)行method2方法钉稍。
NSLock是Cocoa提供給我們最基本的鎖對象,這也是我們經(jīng)常所使用的棺耍,除lock和unlock方法外贡未,NSLock還提供了tryLock和lockBeforeDate:兩個方法,前一個方法會嘗試加鎖,如果鎖不可用(已經(jīng)被鎖住)俊卤,剛并不會阻塞線程嫩挤,并返回NO。lockBeforeDate:方法會在所指定Date之前嘗試加鎖消恍,如果在指定時間之前都不能加鎖岂昭,則返回NO。
2.使用synchronized關鍵字構建的鎖
當然在Objective-C中你還可以用@synchronized指令快速的實現(xiàn)鎖:
//主線程中
TestObj *obj = [[TestObj alloc] init];
//線程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
@synchronized(obj){
[obj method1];
sleep(10);
}
});
//線程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
sleep(1);
@synchronized(obj){
[obj method2];
}
});
@synchronized指令使用的obj為該鎖的唯一標識狠怨,只有當標識相同時约啊,才為滿足互斥,如果線程2中的@synchronized(obj)改為@synchronized(other),剛線程2就不會被阻塞取董,@synchronized指令實現(xiàn)鎖的優(yōu)點就是我們不需要在代碼中顯式的創(chuàng)建鎖對象棍苹,便可以實現(xiàn)鎖的機制,但作為一種預防措施茵汰,@synchronized塊會隱式的添加一個異常處理例程來保護代碼枢里,該處理例程會在異常拋出的時候自動的釋放互斥鎖。所以如果不想讓隱式的異常處理例程帶來額外的開銷蹂午,你可以考慮使用鎖對象栏豺。
3.使用C語言的pthread_mutex_t實現(xiàn)的鎖
//主線程中
TestObj *obj = [[TestObj alloc] init];
__block pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL);
//線程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
pthread_mutex_lock(&mutex);
[obj method1];
sleep(5);
pthread_mutex_unlock(&mutex);
});
//線程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
sleep(1);
pthread_mutex_lock(&mutex);
[obj method2];
pthread_mutex_unlock(&mutex);
});
pthread_mutex_t定義在pthread.h,所以記得#include
4.使用GCD來實現(xiàn)的”鎖”
以上代碼構建多線程我們就已經(jīng)用到了GCD的dispatch_async方法豆胸,其實在GCD中也已經(jīng)提供了一種信號機制奥洼,使用它我們也可以來構建一把”鎖”(從本質(zhì)意義上講,信號量與鎖是有區(qū)別晚胡,具體差異參加信號量與互斥鎖之間的區(qū)別):
//主線程中
TestObj *obj = [[TestObj alloc] init];
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);
[obj method1];
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);
[obj method2];
dispatch_semaphore_signal(semaphore);
});