美文网首页线程锁
NSLock、NSRecursiveLock

NSLock、NSRecursiveLock

作者: liang1030 | 来源:发表于2021-09-02 16:24 被阅读0次

一,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方法当前线程会被阻塞,等到锁释放后才会继续执行。

参考链接:
https://www.jianshu.com/p/22736bb03670

相关文章

网友评论

    本文标题:NSLock、NSRecursiveLock

    本文链接:https://www.haomeiwen.com/subject/brtcwltx.html