多线程编程中,当多个线程访问同一块资源的时候,处理不当,可能会造成数据错乱,数据安全性等问题。解决这个问题就需要保证在访问这块资源的时候只有一个线程,其他想访问的排队等候。所以就要进行锁定,所以使用锁。
按照效率高->低依次看一下

OSSpinLock自旋锁

《不再安全的OSSpinLock》中讲到:如果一个低优先级的线程获得锁并访问共享资源,这时一个高优先级的线程也尝试获得这个锁,它会处于 spin lock 的忙等状态从而占用大量 CPU。此时低优先级线程无法与高优先级线程争夺 CPU 时间,从而导致任务迟迟完不成、无法释放 lock。
所以在我们使用的时候,要将线程置于同一优先级。

-(void)OSSpinLock
{
    __block OSSpinLock oslock = OS_SPINLOCK_INIT;
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        NSLog(@"locking---1");
        OSSpinLockLock(&oslock);
        sleep(5);
        NSLog(@"线程1执行");
        OSSpinLockUnlock(&oslock);
        NSLog(@"unlock---1");
    });
    dispatch_async(queue, ^{
        NSLog(@"locking---2");
        OSSpinLockLock(&oslock);
        NSLog(@"线程2执行");
        OSSpinLockUnlock(&oslock);
        NSLog(@"unlock---2");
    });
}

运行结果

14:12:02.656 [2682:130985] locking---1
14:12:02.656 [2682:130987] locking---2
14:12:07.714 [2682:130985] 线程1执行
14:12:07.714 [2682:130985] unlock---1
14:12:07.715 [2682:130987] 线程2执行
14:12:07.715 [2682:130987] unlock---2

参数说明

OS_SPINLOCK_INIT:默认==0,在lock状态下>0,unlock状态下<0
OSSpinLockLock(&osLock):加锁,参数为osLock地址
OSSpinLockUnlock(&osLock):解锁,参数为osLock地址
OSSpinLockTry(&osLock):尝试加锁,如果可以加锁,则立即加锁并返回YES,如果不可以,则返回NO

dispatch_semaphore

通过控制信号量的值,来控制执行哪个线程。

-(void)semaphore
{
    dispatch_semaphore_t sema = dispatch_semaphore_create(1);
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        NSLog(@"wait---1");
        dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 3.0 * NSEC_PER_SEC));
        NSLog(@"线程1执行");
        dispatch_semaphore_signal(sema);
        NSLog(@"signal---1");
    });
    dispatch_async(queue, ^{
        NSLog(@"wait---2");
        dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, 3.0 * NSEC_PER_SEC));
        NSLog(@"线程2执行");
        dispatch_semaphore_signal(sema);
        NSLog(@"signal---2");
    });
}

dispatch_semaphore_create(x);
当x > 0,并不会发生线程阻塞,而是直接执行了线程1和线程2(看运行时间)。

11:36:29.755 [1717:74601] wait---1
11:36:29.755 [1717:74600] wait---2
11:36:29.756 [1717:74601] 线程1执行
11:36:29.757 [1717:74601] signal---1
11:36:29.757 [1717:74600] 线程2执行
11:36:29.757 [1717:74600] signal---2

当x == 0时,会造成线程阻塞,此时,设置的dispatch_time才会有效

11:39:11.958 [1766:76560] wait---1
11:39:11.958 [1766:76562] wait---2
11:39:14.965 [1766:76562] 线程2执行
11:39:14.965 [1766:76560] 线程1执行
11:39:14.965 [1766:76562] signal---2
11:39:14.966 [1766:76560] signal---1
pthreadMutex互斥锁

是用了pthread中的方法,pthread 是 POSIX 多线程开发框架,是跨平台的 C 语言框架。

#import 
-(void)pthreadMutex
{
    static pthread_mutex_t pthreadLock;
    pthread_mutex_init(&pthreadLock, NULL);
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        NSLog(@"lock---1");
        pthread_mutex_lock(&pthreadLock);
        NSLog(@"线程1执行");
        pthread_mutex_unlock(&pthreadLock);
        NSLog(@"unlock---1");
    });
    dispatch_async(queue, ^{
        NSLog(@"lock---2");
        pthread_mutex_lock(&pthreadLock);
        NSLog(@"线程2执行");
        pthread_mutex_unlock(&pthreadLock);
        NSLog(@"unlock---2");
    });
}

运行结果:一个线程释放之后,另一个线程立即执行

11:41:55.080 [1810:78248] lock---1
11:41:55.080 [1810:78264] lock---2
11:41:55.081 [1810:78248] 线程1执行
11:41:55.082 [1810:78248] unlock---1
11:41:55.082 [1810:78264] 线程2执行
11:41:55.082 [1810:78264] unlock---2
pthread的递归锁
-(void)pthreadMutexattr
{
    static pthread_mutex_t pLock;
    pthread_mutexattr_t attr;
    //初始化attr并且给它赋予默认
    pthread_mutexattr_init(&attr);
    //设置锁类型为递归锁
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&pLock, &attr);
    //销毁一个属性对象,在重新进行初始化之前该结构不能重新使用
    pthread_mutexattr_destroy(&attr);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        static void (^RecursiveBlock)(int);
        RecursiveBlock = ^(int value){
            pthread_mutex_lock(&pLock);
            if (value > 0) {
                NSLog(@"value: %d", value);
                RecursiveBlock(value - 1);
            }
            pthread_mutex_unlock(&pLock);
        };
        RecursiveBlock(5);
    });
}
NSLock
-(void)Lock
{
    NSLock *lock = [[NSLock alloc]init];
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        NSLog(@"locking---1");
        [lock lock];
        NSLog(@"线程1执行");
//        [NSThread sleepForTimeInterval:5];
        [lock unlock];
        NSLog(@"unlocked---1");
    });
    dispatch_async(queue, ^{
        //尝试在指定时间内加锁
        NSLog(@"locking---2");
        BOOL isLocked = [lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:2]];
        if (isLocked) {
            NSLog(@"线程2执行");
            [lock unlock];
            NSLog(@"unlocked---2");
        }else{
            NSLog(@"lockfailed");
        }
    });
}

运行结果

11:52:10.626 [1904:83210] locking---1
11:52:10.626 [1904:83212] locking---2
11:52:10.626 [1904:83210] 线程1执行
11:52:10.628 [1904:83210] unlocked---1
11:52:10.628 [1904:83212] 线程2执行
11:52:10.629 [1904:83212] unlocked---2

[lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:2]];尝试在指定时间内加锁
如果放开[NSThread sleepForTimeInterval:5];这个方法,则尝试加锁失败,运行结果为

11:53:15.561 [1933:84049] locking---1
11:53:15.561 [1933:84047] locking---2
11:53:15.561 [1933:84049] 线程1执行
11:53:17.614 [1933:84047] lockfailed
11:53:20.637 [1933:84049] unlocked---1
Condition锁
-(void)Condition
{
    NSCondition *condition = [[NSCondition alloc]init];
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        [condition lock];
        NSLog(@"locked---1");
        //让一个线程等待一定时间
//        [condition waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
        [condition wait];
        NSLog(@"线程1执行");
        [condition unlock];
        NSLog(@"unlocked---1");
    });
    dispatch_async(queue, ^{
        [condition lock];
        NSLog(@"locked---2");
        [condition wait];
        NSLog(@"线程2执行");
        [condition unlock];
        NSLog(@"unlocked---2");
    });
    dispatch_async(queue, ^{
        sleep(2);
        //唤醒所有等待线程
        NSLog(@"唤醒所有线程");
        [condition broadcast];
        //唤醒一个等待线程
//        NSLog(@"等待唤醒线程");
//        [condition signal];
    });
}

wait:等待
signal:唤醒一个线程
broadcast:唤醒所有等待线程
waitUntilDate:让一个线程等待一定时间

NSRecursiveLock递归锁
-(void)RecursiveLock
{
    NSLock *rLock = [[NSLock alloc]init];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        static void (^RecursiveBlock)(int);
        RecursiveBlock = ^(int value) {
            [rLock lock];
            if (value > 0) {
                NSLog(@"线程%d", value);
                RecursiveBlock(value - 1);
            }
            [rLock unlock];
        };
        RecursiveBlock(4);
    });
}
Synchronized条件锁
-(void)Synchronized
{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        @synchronized (self) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"线程1");
        }
    });
    dispatch_async(queue, ^{
        @synchronized (self) {
            NSLog(@"线程2");
        }
    });
}
NSConditionLock条件锁

最大的特点:可以通过控制condition的值来控制执行顺序,类似添加依赖。

-(void)ConditionLock
{
    NSConditionLock *conLock = [[NSConditionLock alloc]initWithCondition:0];
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        if ([conLock tryLockWhenCondition:0]) {
            NSLog(@"线程1执行");
            [conLock unlockWithCondition:1];
        }else{
            NSLog(@"lockfailed");
        }
    });
    dispatch_async(queue, ^{
        [conLock lockWhenCondition:2];
        NSLog(@"线程2执行");
        [conLock unlockWithCondition:3];
    });
    dispatch_async(queue, ^{
        [conLock lockWhenCondition:1];
        NSLog(@"线程3执行");
        [conLock unlockWithCondition:2];
    });
}

在使用[conLock lockWhenCondition:1];以及[conLock unlockWithCondition:2];时,其实就是对condition做了修改,线程执行的时候会首先去找匹配的condition,运行结果

12:10:57.222 [2143:93635] 线程1执行
12:10:57.222 [2143:93636] 线程3执行
12:10:57.222 [2143:93651] 线程2执行

你可能感兴趣的:(锁)