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

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 <pthread.h>
-(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执行
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容