❓iOS中有哪些锁?
-
@synchronized
一般在创建单例对象的时候使用,来保证在多线程环境下,创建对象是唯一的 -
atomic
修饰属性的关键字,对被修饰对象进行原子操作(对于对象的使用不起作用),例如:
//被atomic修饰的属性
@property(atomic)NSMutableArray *array;
//对被修饰对象进行赋值时,是可以保证线程安全的
self.array = [NSMutableArray array];
//如果对属性进行操作使用时,atomic不能保证线程安全,需要再用其他方式保证线程安全
[self.array addObject:obj];
❓atomic的实现机制是怎样的?为什么在进行被修饰对象赋值操作时可以保证线程安全,操作使用时不能保证线程安全?
-
OSSpinLock
自旋锁
- 含义:Spinlock_t自旋锁是“忙等”的锁,如果当前的锁已被其他线程获取,那么当前线程会不断的探测这个锁是否有被释放,如果释放了则第一时间去获取锁
- 使用场景:自旋锁适用于轻量访问,例如在内存管理中,对引用计数表做操作时只是进行引用计数加1减1操作,是属于轻量访问的,这种场景下可以使用自旋锁
- 区别:自旋锁与普通锁、信号量的锁的区别,信号量的锁,当获取不到锁的时候,它会把自己的线程进行阻塞休眠并释放所持有的资源,等到其他线程释放了锁来唤醒这个休眠的线程
-
NSRecursiveLock
递归锁 特点就是可以重入 NSLock
- (void)test1 {
[lock lock];
[self test2];
[lock unlock];
}
- (void)test2 {
[lock lock];
//业务逻辑
[lock unlock];
}
❌以上代码会造成死锁,NSLock
会造成重入
- (void)test1 {
[recursiveLock lock];
[self test2];
[recursiveLock unlock];
}
- (void)test2 {
[recursiveLock lock];
//业务逻辑
[recursiveLock unlock];
}
✅以上代码使用了递归锁,可以避免重入
-
dispatch_semaphore_t
信号量(记录型信号量)
- 常用API
//创建信号量
dispatch_semaphore_create(1);
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(semaphore);
- 实现原理
------❗️当调用dispatch_semaphore_create(1)创建信号量时,实现原理如下:-------
//实例化了一个结构体
struct semaphore {
int value;//信号量的值
List<thread>;//线程列表/队列
}
------❗️当调用dispatch_semaphore_wait时,实现原理如下:-------
dispatch_semaphore_wait() {
S.value = S.value - 1;//先对信号量结构体的成员value即信号量的值减1
/*
如果信号量的值减1后小于0了,
意味的当前没有资源可以访问了或者说当前不能获取这个信号量,
于是当前要获取信号量的这个线程,通过一个主动的阻塞行为,将自身阻塞,进入S.List队列中等待
*/
if S.value < 0 then Block(S.List);
}
------❗️当调用dispatch_semaphore_signal时,实现原理如下:-------
dispatch_semaphore_signal() {
S.value = S.value + 1;;//先对信号量结构体的成员value即信号量的值加1
/*
如果信号量的值加1后仍然小于等于0,
意味在释放信号之前,有队列在排队等待获取这个信号量,即队列中有阻塞等待的线程需要唤醒
于是将对应的线程进行唤醒,唤醒是一个被动行为,由释放信号的线程来唤醒被阻塞的线程
*/
if S.value <= 0 then wakeup(S.List);
}
网友评论