很多人遇到过类似这样的业务场景, 例如一共有50张车票要卖,当只有一个售票点时一张一张卖没有问题,但是当有多个售票点时,每次售票需要查询是否还有票,也就是说售票出票这个动作同一时间只能一个地方完成。 于是列举iOS一些常见的锁来实现此功能。
1.@synchronized
互斥锁,@synchronized(self)里面的self是锁的标识,一样标识方可互斥@synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁
2.dispatch_semaphore
dispatch_semaphore是GCD用来同步的一种方式,与他相关的共有三个函数,分别是:
A.dispatch_semaphore_create(long value); 传入参数long型,输出一个dispatch_semaphore_t 类型值为value的信号量
B.dispatch_semaphore_signal(dispath_semaphore_t dsema); 传入的信号量dsema会在这加1
C.dispatch_semaphore_wait(dispatch_semaphore_t desma,dispathc_time_t timeout); 如果传入的信号量大于0,则信号量会在这减1,并继续执行下面的语句,如果信号量为0,这阻塞当前线程等待timeout时间,如果等待时间内信号量被B函数加一了,则能减1并继续执行,如果等待时间没有获取到信号量大于0,则等待时间到时继续执行后面。 (所以经常把信号量设为1, 时间设为无限大来实现互斥)
3.NSLock(包括NSRecursiveLock递归锁 NSConditionLock条件锁等)
- @protocol NSLocking
- - (void)lock;
- - (void)unlock;
- @end
- @interface NSLock : NSObject {
- @private
- void *_priv;
- }
- - (BOOL)tryLock;
- - (BOOL)lockBeforeDate:(NSDate *)limit;
- @property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);
- @end
4.pthread_mutex
c语言下定义的多线程加锁方法。
Demo中有三个方法,分别代表1.一个售票点,一人售票;2.俩个售票点,各有一人售票;3.俩个售票点,一个俩人售票,一个三人售票。
实现方法分别为:
- (IBAction)oneTicketBooking:(id)sender {
if (![self preparatoryStage]) {
return;
}
//一个队列 一个线程
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
[self saleTicket];
}];
}
- (IBAction)twoTicketBooking:(id)sender {
if (![self preparatoryStage]) {
return;
}
//俩个队列 每个里面一个线程
//1.创建队列代表车票售卖窗口1
NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
// NSOperationQueue *queue1 = [NSOperationQueue mainQueue];//如果加入主队了则安全的 因为其为串行队列 但是耗时操作会阻塞
queue1.maxConcurrentOperationCount = 1;
//2.创建队列代表车票售卖窗口2
NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
queue1.maxConcurrentOperationCount = 1;
//创建卖票操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicket];
}];
//创建卖票操作
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicket];
}];
//开始
[queue1 addOperation:op1];
[queue2 addOperation:op2];
}
- (IBAction)fiveTicketBooking:(id)sender {
if (![self preparatoryStage]) {
return;
}
//俩个队列 每个里面多个线程
//1.创建队列代表车票售卖窗口1
NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
// NSOperationQueue *queue1 = [NSOperationQueue mainQueue];//如果加入主队了则安全的 因为其为串行队列 但是耗时操作会阻塞
queue1.maxConcurrentOperationCount = 1;
//2.创建队列代表车票售卖窗口2
NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
queue1.maxConcurrentOperationCount = 1;
//创建卖票操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicket];
}];
//创建卖票操作
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicket];
}];
//创建卖票操作
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicket];
}];
//创建卖票操作
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicket];
}];
//创建卖票操作
NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicket];
}];
//开始
[queue1 addOperation:op1];
[queue1 addOperation:op2];
[queue2 addOperation:op3];
[queue2 addOperation:op4];
[queue2 addOperation:op5];
}
用NSOperation和NSOperationQueue来模拟。
当不使用任何锁时直接进行售票操作类似这样:
#pragma Mark 非线程安全
- (void)saleTicketNoSafe{
while (1) {
if (self.ticketNumber > 0) {
self.ticketNumber--;
[NSThread sleepForTimeInterval:0.2];
NSLog(@"剩余票数:%d 窗口:%@", self.ticketNumber, [NSThread currentThread]);
}
if (self.ticketNumber <= 0) {
NSLog(@"本次出票失败");
break;
}
}
}
而加了锁之后的打印结果为
详情见Demo
***以上 项目名称TYNDemoLockInOC
(欢迎随手给一颗星星哦~)本篇博客Demo地址https://github.com/xmy0010/DemoForCSDN
本人邮箱18144200589@163.com欢迎小伙伴一起讨论,学习,进步。