NSLock
是 Objective-C 提供的一种 轻量级互斥锁,用于保证多线程访问共享资源的安全性。相比 @synchronized
,它的性能更好,并且提供了更灵活的锁管理方法。
1. NSLock
的基本使用
1)lock和unlock
@interface SafeCounter : NSObject
@property (nonatomic, strong) NSLock *lock;
@property (nonatomic, assign) NSInteger count;
@end@implementation SafeCounter- (instancetype)init {if (self = [super init]) {_lock = [[NSLock alloc] init];}return self;
}- (void)increment {[self.lock lock]; // 加锁self.count += 1;NSLog(@"当前 count: %ld", (long)self.count);[self.lock unlock]; // 解锁
}@end
lock
确保 count
在多个线程访问时不会竞争,避免数据错乱。lock
后必须 unlock
,否则会导致死锁。
2)我们还可以使用tryLock
(尝试加锁,不阻塞),如果 tryLock
获取到锁,返回 YES
,否则返回 NO
,不会阻塞线程:
if ([self.lock tryLock]) {// 线程安全代码[self.lock unlock];
} else {NSLog(@"锁已被占用,执行其他逻辑");
}
适用于低优先级任务,避免等待锁导致线程卡住。
3)lockBeforeDate:
(限时加锁)
设置超时时间,超过这个时间还拿不到锁,就放弃:
if ([self.lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:2]]) {// 线程安全代码[self.lock unlock];
} else {NSLog(@"超时未获取到锁");
}
适用于有时间敏感性的任务,防止线程长时间等待锁。
2. NSLock
能解决哪些问题?
-
防止数据竞争
- 例如多个线程同时读写
NSMutableArray
、NSMutableDictionary
时可能崩溃,NSLock
可以确保一个线程完成操作后,另一个线程才能访问。
- 例如多个线程同时读写
-
避免死锁
NSLock
提供tryLock
和lockBeforeDate:
方法,可以防止线程长时间等待锁,降低死锁的风险。
-
提高
@synchronized
的性能-
@synchronized
内部也是基于NSLock
实现的,但多了一些管理开销,因此NSLock
更轻量,性能更高。
-
3、注意事项
避免多个线程交叉锁(死锁)
如果一个线程持有 lock1
,等待 lock2
,而另一个线程持有 lock2
,等待 lock1
,就会产生死锁:
[self.lock1 lock];
[self.lock2 lock]; // 这里可能导致死锁
[self.lock2 unlock];
[self.lock1 unlock];
正确做法:
- 尽量保持加锁顺序一致,避免交叉等待。
- 考虑用
tryLock
失败时执行其他逻辑。
总结
NSLock
是@synchronized
的更轻量级版本,适合需要手动管理锁的场景。- 支持
tryLock
和lockBeforeDate:
,可以避免死锁,提高程序的健壮性。 - 必须保证
lock
之后一定unlock
,避免死锁或线程卡死。 - 适用于高频加锁解锁场景,但不支持递归调用(可用
NSRecursiveLock
代替)。