iOS中的线程锁(关于@synchronized)

503 阅读2分钟

「这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战

@synchronized(递归锁)

@synchronized 概念

@synchronized 结构所做的事情跟 NSLock,更准确的说法应该是递归锁 NSRecursiveLock 类似。@synchronized 可以防止不同的线程同时执行同一段代码。但在某些情况下,相比于使用 NSLock 创建锁对象、加锁和解锁来说,@synchronized 用着更方便,可读性更高, 自然效率会比较低

@synchronized 作用

@synchronized 的作用是创建一个互斥锁,保证此时没有其它线程对 self 对象进行修改,保证代码的安全性。也就是包装这段代码是原子性的,安全的。这个是 objective-c 的一个锁定令牌,防止 self 对象在同一时间内被其他线程访问,起到保护线程安全的作用

@synchronized 用法

首先 @synchronized() 小括号内需要一个参数,这个参数就表示信号量。这个参数可以是任何对象,包括 self,或者是自定义的信号量。针对不同的操作应该定义不同的信号量

@synchronized() {…} 大括号中就是要加锁执行的代码,代码会操作一些数据。当开始执行代码时,意味着当前线程对其加锁了,当代码执行完后,自动解锁,其他线程才允许执行此段代码

- (void)lockData  {  
    @synchronized(self){  
        // 关键代码;  
    }  
}  

@synchronized 常用场景

之前在iOS中的多线程(多线程的竞争)用到过

示例:

- (void)saleTicket{

    while (1) {
        NSLog(@"进行卖票-%@",[NSThread currentThread].name);
        // @synchronized (锁对象),锁对象必须是一个,表示记录状态,一般用self就可以
        @synchronized (self) {
        
            NSInteger count = self.ticketCount;
            if (count > 0 ){
                self.ticketCount = count - 1;
                NSLog(@"%@卖了一张票,还剩%ld张",[NSThread currentThread].name,(long)self.ticketCount);
            }else{
                NSLog(@"票卖完了");
                break;
            }
        }
    }
}

值得一提的是这个加锁机制是支持递归的,如果加锁的代码在当前线程中递归调用自身,那么会持续保持加锁状态,其余线程还是访问不了,只有当递归完成全部执行完后,或者出错报异常退出后,锁才会解开,释放信号量,其余线程才允许操作此段代码块