iOS锁

锁的作用:保证线程安全。
锁的分类:互斥锁自旋锁,其它比如条件锁,递归锁,信号量都是上层的封装和实现。

互斥锁

防止两条线程同时对同一公共资源进行读写的机制。当获取锁操作失败时,线程会进入睡眠,等待锁释放时被唤醒。

互斥锁分为:

  • 递归锁:可重入锁,同一个线程在锁释放前可再次获取锁,可以递归调用
  • 非递归锁:不可重入,必须等锁释放后才能再次获取锁。

自旋锁

线程反复检查锁变量是否可用。由于线程在这一过程中保持执行,因此是一种忙等待。一旦获取自旋锁,线程会一直保持该锁,直到显式释放。
优点:避免了线程的上下文调度开销,因此对于线程只会阻塞很短时间的场景很有用。

互斥锁和自旋锁区别

  • 互斥锁在线程没获取到锁时,线程会进入休眠状态,等锁被释放时会被唤醒
  • 自旋锁的线程会一直处于等待(忙等待),不会进入休眠,效率高。

自旋锁种类

1. OSSpinLock

自旋锁存在不安全机制,因为自旋锁会让线程处于忙等待,因此高优先级的线程可能一直占用CPU,造成低优先级的任务无法执行,不能释放锁。

2. 读写锁

  • 写是排他的,同时只能有一个写或者多个读,但不能同时读写。
  • 若当前没有读写,写可以立即获得读写锁,否则必须等待没有任何读写者。如果没有写,读可以立即获得锁,否则不谢等写释放锁。

互斥锁

pthread_mutex

全局声明
#import <pthread.h>

pthread_mutex_t _lock;
- (void)addCount {
    pthread_mutex_lock(&_lock);
    for (int i = 0; i < 10; i++) {
        self.count += 1;
        NSLog(@"----- %d", self.count);
    }
    pthread_mutex_unlock(&_lock);
}

- (void)method1 {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self addCount];
    });
}

- (void)method2 {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self addCount];
    });
}

@synchronized

@synchronized (self) {
        for (int i = 0; i < 10; i++) {
            self.count += 1;
            NSLog(@"----- %d", self.count);
        }
    }
  1. 不能使用非OC对象作为加锁条件——id2data中接收参数为id类型
  2. 多次锁同一个对象会有什么后果吗——会从高速缓存中拿到data,所以只会锁一次对象
  3. 都说@synchronized性能低——是因为在底层增删改查消耗了大量性能
  4. 加锁对象不能为nil,否则加锁无效,不能保证线程安全

NSLock

是对互斥锁的简单封装

    [self.lock lock];
    //[self.lock lock] 重复两次会造成线程永久锁死
    for (int i = 0; i < 10; i++) {
        self.count += 1;
        NSLog(@"----- %d", self.count);
    }
    [self.lock unlock];

NSLock在解锁前不能重复加锁。

NSRecursiveLock

可重复加锁

dispatch_semaphore

NSCondition

NSConditionLock

性能对比


性能对比.png

参考:https://juejin.im/post/5ec9f3ec6fb9a047f0125fd2#heading-32

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。