一,NSLock
1,使用方法:
//加锁
- (void)lock;
//解锁
- (void)unlock;
//试图得到一个锁。YES:成功得到锁;NO:没有得到锁。
- (BOOL)tryLock;
/*在指定的时间以前得到锁。YES:在指定时间之前获得了锁;NO:在指定时间之前没有获得锁。
该线程将被阻塞,直到获得了锁,或者指定时间过期。
*/
- (BOOL)lockBeforeDate:(NSDate *)limit;
//为锁指定一个名称
@property (nullable, copy) NSString *name;
2,举例:
- (void)saleTicket {
//此时资源同一时刻只能被一个线程访问
[_lock lock];
if (tickets>0) {
tickets--;
}else {
NSLog(@"票已经售磬了!");
}
[_lock unlock];
}
注:
You should not use this class to implement a recursive lock. Calling the lock method twice on the same thread will lock up your thread permanently.
在同一个线程上两次调用lock方法将永久锁定线程
二,NSRecursiveLock
简介:
NSRecursiveLock defines a lock that may be acquired multiple times by the same thread without causing a deadlock, a situation where a thread is permanently blocked waiting for itself to relinquish a lock. While the locking thread has one or more locks, all other threads are prevented from accessing the code protected by the lock.
NSRecursiveLock定义了一个锁,该锁可以被同一个线程多次获取而不会导致死锁,死锁是一种线程永久阻塞等待自己放弃锁的情况。当锁定线程有一个或多个锁时,所有其他线程都被阻止访问受该锁保护的代码。
注:
1,在同一个线程中多次 lock 不会造成死锁 但是可能会造成线程等待
2,如果锁在 线程A 中 lock 了 并没有解锁, 那么在其他线程如果调用了该锁(除trylock外)的方法就会造成 该线程的等待,直到 线程A的锁unlock
3,如果锁在 线程A 中 lock 了 并没有解锁, 在线程A中 trylock 返回 YES ,并再 lock 一次,此时需要增加 unlock 操作
4,如果锁在 线程A 中 lock 了 并没有解锁,在其他线程 trylock 返回NO , 如果这个线程没有调用 lock 方法 即 只调用trylock 或者 unlock 方法, 不会造成线程等待,该线程的任务会继续走下去, 造成没有 lock 的现象
验证:
2,如果锁在 线程A 中 lock 了 并没有解锁, 那么在其他线程如果调用了该锁(除trylock外)的方法就会造成 该线程的等待,直到 线程A的锁unlock
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic, strong) NSRecursiveLock *myLock;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.myLock = [[NSRecursiveLock alloc] init];
[self testBlock];
}
//加锁
- (void)lock {
if ([_myLock tryLock]) {
NSLog(@"%@ try lock ",[NSThread currentThread]);
return;
} else{
NSLog(@"%@ try lock fail",[NSThread currentThread]);
}
NSLog(@"%@ lock",[NSThread currentThread]);
[_myLock lock];
}
//解锁
-(void)unlock {
NSLog(@"%@ unlock",[NSThread currentThread]);
[_myLock unlock];
}
- (void)testBlock {
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
NSThread *thread = [NSThread currentThread];
thread.name = @"add";
[weakSelf lock];
for (int i = 0; i < 2; i++) {
NSLog(@"%@ add ",[NSThread currentThread]);
}
sleep(5);
[weakSelf unlock];
});
dispatch_async(dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
sleep(1);
NSLog(@"------remove-thread----------");
NSThread *thread = [NSThread currentThread];
thread.name = @"remove";
[weakSelf.myLock lock];
NSLog(@"%@ remove",[NSThread currentThread]);
[weakSelf.myLock unlock];
});
}
@end
输出:
2021-09-02 16:57:03.525624+0800 LockTest[32152:15453230] <NSThread: 0x283f5e040>{number = 5, name = add} try lock
2021-09-02 16:57:03.525713+0800 LockTest[32152:15453230] <NSThread: 0x283f5e040>{number = 5, name = add} add
2021-09-02 16:57:03.525750+0800 LockTest[32152:15453230] <NSThread: 0x283f5e040>{number = 5, name = add} add
2021-09-02 16:57:04.530878+0800 LockTest[32152:15453229] ------remove-thread----------
2021-09-02 16:57:08.531263+0800 LockTest[32152:15453230] <NSThread: 0x283f5e040>{number = 5, name = add} unlock
2021-09-02 16:57:08.532001+0800 LockTest[32152:15453229] <NSThread: 0x283f0d840>{number = 4, name = remove} remove
可以发现remove总在add线程调用unlock之后才执行。
4,如果锁在 线程A 中 lock 了 并没有解锁,在其他线程 trylock 返回NO , 如果这个线程没有调用 lock 方法 即 只调用trylock 或者 unlock 方法, 不会造成线程等待,该线程的任务会继续走下去, 造成没有 lock 的现象
//将testBlock方法中第二个线程改为以下代码
dispatch_async(dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
sleep(1);
NSLog(@"------remove-thread----------");
NSThread *thread = [NSThread currentThread];
thread.name = @"remove";
[weakSelf.myLock tryLock];
NSLog(@"-----------1111--------------");
});
[weakSelf.myLock tryLock]; 时的输出:
2021-09-02 17:52:45.941894+0800 LockTest[32980:15485823] <NSThread: 0x282cb0cc0>{number = 3, name = add} try lock
2021-09-02 17:52:45.941984+0800 LockTest[32980:15485823] <NSThread: 0x282cb0cc0>{number = 3, name = add} add
2021-09-02 17:52:45.942020+0800 LockTest[32980:15485823] <NSThread: 0x282cb0cc0>{number = 3, name = add} add
2021-09-02 17:52:46.946643+0800 LockTest[32980:15485820] ------remove-thread----------
2021-09-02 17:52:46.946861+0800 LockTest[32980:15485820] -----------1111--------------
2021-09-02 17:52:50.944810+0800 LockTest[32980:15485823] <NSThread: 0x282cb0cc0>{number = 3, name = add} unlock
[weakSelf.myLock lock]; 时的输出:
2021-09-02 17:53:38.275857+0800 LockTest[33045:15486653] <NSThread: 0x28068a300>{number = 6, name = add} try lock
2021-09-02 17:53:38.275938+0800 LockTest[33045:15486653] <NSThread: 0x28068a300>{number = 6, name = add} add
2021-09-02 17:53:38.275972+0800 LockTest[33045:15486653] <NSThread: 0x28068a300>{number = 6, name = add} add
2021-09-02 17:53:39.277999+0800 LockTest[33045:15486651] ------remove-thread----------
2021-09-02 17:53:43.281188+0800 LockTest[33045:15486653] <NSThread: 0x28068a300>{number = 6, name = add} unlock
2021-09-02 17:53:43.281388+0800 LockTest[33045:15486651] -----------1111--------------
说明tryLock返回为NO时不会阻塞当前线程,下面的代码会执行。如果调用的是lock方法当前线程会被阻塞,等到锁释放后才会继续执行。
网友评论