美文网首页线程锁
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