最近突然想了解了解保持線程同步的方式@synchronized跨释、NSLock僻孝、dispatch_semaphore、NSCondition
@synchronized() :方式一
NSObject *obj = [[NSObject alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(obj) {
NSLog(@"需要線程同步的操作1 開始");
NSLog(@"需要線程同步的操作1 結(jié)束");
}
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(obj) {
NSLog(@"需要線程同步的操作2");
}
});
輸出記
?需要線程同步的操作1 開始
需要線程同步的操作1 結(jié)束
需要線程同步的操作2
方式二:
NSObject *obj = [[NSObject alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(obj) {
NSLog(@"需要線程同步的操作1 開始");
NSLog(@"需要線程同步的操作1 結(jié)束");
}
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(self) {
NSLog(@"需要線程同步的操作2");
}
});
輸出結(jié)果:
需要線程同步的操作2
需要線程同步的操作1 開始
需要線程同步的操作1 結(jié)束
從方式一和二 的輸出不難看出兩者的不同 @synchronized(name) 當(dāng)那么相同時(shí)線程順序輸出,反之,輸入順序不確定
dispatch_semaphore
dispatch_semaphore_t signal = dispatch_semaphore_create(1);
dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(signal, overTime);
NSLog(@"需要線程同步的操作1 開始");
NSLog(@"需要線程同步的操作1 結(jié)束");
dispatch_semaphore_signal(signal);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(signal, overTime);
NSLog(@"需要線程同步的操作2");
dispatch_semaphore_signal(signal);
});
需要線程同步的操作1 開始
需要線程同步的操作1 結(jié)束
需要線程同步的操作2
dispatch_semaphore是GCD用來同步的一種方式崇决,與他相關(guān)的共有三個(gè)函數(shù)材诽,分別是dispatch_semaphore_create,dispatch_semaphore_signal恒傻,dispatch_semaphore_wait脸侥。
(1)dispatch_semaphore_create的聲明為:
dispatch_semaphore_t? dispatch_semaphore_create(long value);
傳入的參數(shù)為long,輸出一個(gè)dispatch_semaphore_t類型且值為value的信號量盈厘。
值得注意的是睁枕,這里的傳入的參數(shù)value必須大于或等于0,否則dispatch_semaphore_create會返回NULL扑庞。
(2)dispatch_semaphore_signal的聲明為:
long dispatch_semaphore_signal(dispatch_semaphore_t dsema)
這個(gè)函數(shù)會使傳入的信號量dsema的值加1譬重;
(3) dispatch_semaphore_wait的聲明為:
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
這個(gè)函數(shù)會使傳入的信號量dsema的值減1罐氨;這個(gè)函數(shù)的作用是這樣的,如果dsema信號量的值大于0滩援,該函數(shù)所處線程就繼續(xù)執(zhí)行下面的語句栅隐,并且將信號量的值減1;如果desema的值為0玩徊,那么這個(gè)函數(shù)就阻塞當(dāng)前線程等待timeout(注意timeout的類型為dispatch_time_t租悄,不能直接傳入整形或float型數(shù)),如果等待的期間desema的值被dispatch_semaphore_signal函數(shù)加1了恩袱,且該函數(shù)(即dispatch_semaphore_wait)所處線程獲得了信號量泣棋,那么就繼續(xù)向下執(zhí)行并將信號量減1。如果等待期間沒有獲取到信號量或者信號量的值一直為0畔塔,那么等到timeout時(shí)潭辈,其所處線程自動執(zhí)行其后語句。
dispatch_semaphore 是信號量澈吨,但當(dāng)信號總量設(shè)為 1 時(shí)也可以當(dāng)作鎖來把敢。在沒有等待情況出現(xiàn)時(shí),它的性能比 pthread_mutex 還要高谅辣,但一旦有等待情況出現(xiàn)時(shí)修赞,性能就會下降許多。相對于 OSSpinLock 來說桑阶,它的優(yōu)勢在于等待時(shí)不會消耗 CPU 資源柏副。
NSLock
NSLock *lock = [[NSLock alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//[lock lock];
[lock lockBeforeDate:[NSDate date]];
NSLog(@"需要線程同步的操作1 開始");
NSLog(@"需要線程同步的操作1 結(jié)束");
[lock unlock];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if ([lock tryLock]) {//嘗試獲取鎖,如果獲取不到返回NO蚣录,不會阻塞該線程
NSLog(@"鎖可用的操作");
[lock unlock];
}else{
NSLog(@"鎖不可用的操作");
}
NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:3];
if ([lock lockBeforeDate:date]) {//嘗試在未來的3s內(nèi)獲取鎖割择,并阻塞該線程,如果3s內(nèi)獲取不到恢復(fù)線程, 返回NO,不會阻塞該線程
NSLog(@"沒有超時(shí)包归,獲得鎖");
[lock unlock];
}else{
NSLog(@"超時(shí)锨推,沒有獲得鎖");
}
});
NSLock是Cocoa提供給我們最基本的鎖對象铅歼,這也是我們經(jīng)常所使用的,除lock和unlock方法外换可,NSLock還提供了tryLock和lockBeforeDate:兩個(gè)方法贮预,前一個(gè)方法會嘗試加鎖,如果鎖不可用(已經(jīng)被鎖住)瓣距,剛并不會阻塞線程响疚,并返回NO。lockBeforeDate:方法會在所指定Date之前嘗試加鎖译荞,如果在指定時(shí)間之前都不能加鎖瓤的,則返回NO。
NSRecursiveLock遞歸鎖
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 = %d", value);
RecursiveMethod(value - 1);
}
[lock unlock];
};
RecursiveMethod(5);
});
NSRecursiveLock實(shí)際上定義的是一個(gè)遞歸鎖吞歼,這個(gè)鎖可以被同一線程多次請求圈膏,而不會引起死鎖。這主要是用在循環(huán)或遞歸操作中篙骡。
NSConditionLock
NSConditionLock * lock = [NSConditionLock new];
NSMutableArray *products = [NSMutableArray array];
NSInteger HAS_DATA = 1;
NSInteger NO_DATA = 0;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (1) {
[lock lockWhenCondition:NO_DATA];
[products addObject:[[NSObject alloc] init]];
NSLog(@"produce a product,總量:%zi",products.count);
[lock unlockWithCondition:HAS_DATA];
}
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (1) {
NSLog(@"wait for product");
[lock lockWhenCondition:HAS_DATA];
[products removeObjectAtIndex:0];
NSLog(@"custome a product");
[lock unlockWithCondition:NO_DATA];
}
});
NSCondition
NSCondition *condition = [[NSCondition alloc] init];
NSMutableArray *products = [NSMutableArray array];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (1) {
[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 (1) {
[condition lock];
[products addObject:[[NSObject alloc] init]];
NSLog(@"produce a product,總量:%zi",products.count);
[condition signal];
[condition unlock];
}
});
[condition lock];一般用于多線程同時(shí)訪問稽坤、修改同一個(gè)數(shù)據(jù)源,保證在同一時(shí)間內(nèi)數(shù)據(jù)源只被訪問糯俗、修改一次尿褪,其他線程的命令需要在lock 外等待,只到unlock 得湘,才可訪問
[condition unlock];與lock 同時(shí)使用
[condition wait];讓當(dāng)前線程處于等待狀態(tài)
[condition signal];CPU發(fā)信號告訴線程不用在等待杖玲,可以繼續(xù)執(zhí)行