iOS 常用各种锁来模拟卖票功能

很多人遇到过类似这样的业务场景, 例如一共有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条件锁等)

  1. @protocol NSLocking  
  2. - (void)lock;  
  3. - (void)unlock;  
  4. @end  
  5. @interface NSLock : NSObject  {  
  6. @private  
  7.     void *_priv;  
  8. }  
  9. - (BOOL)tryLock;  
  10. - (BOOL)lockBeforeDate:(NSDate *)limit;  
  11. @property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);  
  12. @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欢迎小伙伴一起讨论,学习,进步。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值