主要內(nèi)容
- NSLock系
- @synchronized
- dispatch_semaphore_t
NSLock系
NSLock
NSLock *lock = [NSLock new];
for(NSInteger i = 0; i < 3; i++)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lock];
NSLog(@"%ld", i);
[NSThread sleepForTimeInterval:1];
[lock unlock];
});
}
結(jié)果(注意時(shí)間)
19:28:12.846 ObjectiveDemo[1146:728046] 0
19:28:13.850 ObjectiveDemo[1146:728047] 1
19:28:14.853 ObjectiveDemo[1146:728048] 2
NSLock還提供了tryLock和lockBeforeDate兩個(gè)方法
- tryLock 嘗試加鎖,如果鎖已經(jīng)被鎖住,不會(huì)阻塞線程,并返回NO
- lockBeforeDate 方法會(huì)在所指定Date之前嘗試加鎖,如果在指定時(shí)間之前都不能加鎖,則返回NO
NSLock *lock = [NSLock new];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[lock lock];
NSLog(@"1");
[NSThread sleepForTimeInterval:2.0];
[lock unlock];
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
if([lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:10.0]])
{
NSLog(@"lock Success");
[lock unlock]
}
else
{
NSLog(@"lock Failure");
}
});
結(jié)果(注意時(shí)間)
19:36:37.409 ObjectiveDemo[1161:732625] 1
19:36:39.413 ObjectiveDemo[1161:732632] lock Success
NSConditionLock(條件鎖)
NSConditionLock *lock = [[NSConditionLock alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lockWhenCondition:12];
NSLog(@"1");
[lock unlock];
});
[NSThread sleepForTimeInterval:1.0];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lock];
NSLog(@"2");
[lock unlockWithCondition:12];
});
結(jié)果
09:17:10.458 ObjectiveDemo[659:9989] 2
09:17:10.458 ObjectiveDemo[659:9993] 1
解釋:第一個(gè)線程進(jìn)入時(shí)鎖住,設(shè)置條件為12,第二個(gè)線程運(yùn)行時(shí)鎖住,沒有條件也沒有其它的鎖在執(zhí)行,所以就開始執(zhí)行,完了解開12的鎖,第一線程那里就打開了
注意
- 使用initWithCondition初始化鎖時(shí)這時(shí)這把鎖是在當(dāng)前條件下是打開的,默認(rèn)初始條件為0
- NSConditionLock的實(shí)例同一時(shí)刻最多只有一個(gè)條件可以解鎖
消費(fèi)者和生產(chǎn)者模型
NSConditionLock *lock = [[NSConditionLock alloc] init];
NSMutableArray *produce = [NSMutableArray array];
//消費(fèi)者
void(^consumer)(NSInteger) = ^(NSInteger condition){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lockWhenCondition:condition];
NSLog(@"consumer: %@", produce.firstObject);
[produce removeObjectAtIndex:0];
[lock unlock];
});
};
//生成者
void(^producer)(NSInteger num) = ^(NSInteger num){
for(NSInteger i = 1; i <= num; i++)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lock];
[produce addObject:@(i)];
NSLog(@"producer: %ld", i);
[NSThread sleepForTimeInterval:1];
[lock unlockWithCondition:i];
});
}
};
consumer(1);
consumer(2);
consumer(3);
producer(3);
結(jié)果
09:30:50.745 ObjectiveDemo[731:18789] producer: 1
09:30:51.750 ObjectiveDemo[731:18780] consumer: 1
09:30:51.751 ObjectiveDemo[731:18813] producer: 2
09:30:52.754 ObjectiveDemo[731:18812] consumer: 2
09:30:52.755 ObjectiveDemo[731:18886] producer: 3
09:30:53.760 ObjectiveDemo[731:18814] consumer: 3
NSCondition 斷言
在使用條件鎖實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者關(guān)系時(shí)由于需要不斷修改關(guān)系所以代碼比較難看,NSCondition可以優(yōu)雅的實(shí)現(xiàn)
NSCondition *condition = [[NSCondition alloc] init];
NSMutableArray *produce = [NSMutableArray array];
//消費(fèi)者
void(^consumer)(void) = ^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[condition lock];
while(produce.count == 0)
{
[condition wait];
}
NSLog(@"consumer: %@", produce.firstObject);
[produce removeObjectAtIndex:0];
[condition unlock];
});
};
//生成者
void(^producer)(NSInteger num) = ^(NSInteger num){
for(NSInteger i = 1; i <= num; i++)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[condition lock];
[produce addObject:@(i)];
NSLog(@"producer: %ld", i);
[condition signal];
[NSThread sleepForTimeInterval:1];
[condition unlock];
});
}
};
consumer();
consumer();
consumer();
producer(3);
結(jié)果
09:45:56.659 ObjectiveDemo[802:28917] producer: 1
09:45:57.660 ObjectiveDemo[802:28825] producer: 2
09:45:58.664 ObjectiveDemo[802:28918] producer: 3
09:45:59.669 ObjectiveDemo[802:28852] consumer: 1
09:45:59.669 ObjectiveDemo[802:28853] consumer: 2
09:45:59.670 ObjectiveDemo[802:28817] consumer: 3
注意:signal一次只能喚醒一個(gè)wait,如果有多個(gè)wait可以使用broadcast
1.4 NSRecursiveLock 遞歸鎖
在有需求實(shí)現(xiàn)遞歸調(diào)用,但是實(shí)現(xiàn)部分又得加鎖,如果使用普通鎖,就會(huì)造成死鎖,比如下面
- (void)recursiveCount:(NSInteger)count
{
static NSLock *lock;
lock = lock ? lock : [NSLock new];
[lock lock];
if(count)
{
NSLog(@"start:%ld", count);
[NSThread sleepForTimeInterval:1];
[self recursiveCount:count - 1];
NSLog(@"end:%ld", count);
}
[lock unlock];
}
解釋:end是無法輸出的,因?yàn)樵谒坝诌f歸調(diào)用了,到了鎖的時(shí)候發(fā)現(xiàn)上一個(gè)鎖還沒完成然后就開始等待,使用遞歸鎖可以解決
- (void)recursiveCount:(NSInteger)count
{
static NSRecursiveLock *lock;
lock = lock ? lock : [NSRecursiveLock new];
[lock lock];
if(count)
{
NSLog(@"start:%ld", count);
[NSThread sleepForTimeInterval:1];
[self recursiveCount:count - 1];
NSLog(@"end:%ld", count);
}
[lock unlock];
}
結(jié)果
10:25:29.171 ObjectiveDemo[884:46332] start:2
10:25:30.173 ObjectiveDemo[884:46332] start:1
10:25:31.174 ObjectiveDemo[884:46332] end:1
10:25:31.175 ObjectiveDemo[884:46332] end:2
@synchronized
這是一種非常簡潔而且安全的加鎖方式,內(nèi)部自動(dòng)判斷了當(dāng)前使用加鎖的方式(遞歸鎖的判斷)
- (void)recursiveCount:(NSInteger)count
{
@synchronized (self) {
if(count)
{
NSLog(@"start:%ld", count);
[NSThread sleepForTimeInterval:1];
[self recursiveCount:count - 1];
NSLog(@"end:%ld", count);
}
}
}
注意:@synchronized (obj)只是對(duì)同一個(gè)obj進(jìn)行互斥
dispatch_semaphore_t
這是通過GCD的信號(hào)來加鎖的,在我的GCD中已經(jīng)講過,可以去那了解一下,不怎么建議使用這種方式加鎖。因?yàn)檫@是實(shí)現(xiàn)并發(fā)用的,只是把并發(fā)數(shù)設(shè)置為1,就有了鎖的效果了