美文网首页
多线程异步安全,安全锁的问题

多线程异步安全,安全锁的问题

作者: 上帝是个女孩丶 | 来源:发表于2017-10-24 18:13 被阅读85次

    本篇文章主要介绍多线程在异步时候的内部代码调用。以及加锁时候代码的调用。比较明显的使用地点是数据库操作。资源竞争。
    首先我们常用到的锁有以下几种:

    @synchronizad、atomic、NSLook、NSRecursiveLock(递归锁)



    接下来先逐一简单介绍一下这些个线程锁:

    1. @synchronizad

    这个是常规的局部代码锁。使用方式:

    @synchronized(lock){
    
         A代码
    }
    @synchronized(lock){
    
         B代码
    }    
    

    lock 是id类型,只要求唯一性就可以。通常用self即可

    加密后相当于队列效果,执行完A之后才会执行B。即便是两个异步线程。

    2.aotomic

    这个属于属性锁,也就是原子操作。一个@property使用了这个关键字之后,他的setter方法会自动枷锁。加锁方式用的就是@synchronizad。 但是这个属性不要随便乱用,第一他的性能消耗太高,是noaotomic的20倍差不多。而且,仅仅对setter方法加锁是有漏洞的,具体例子就是读取和set的顺序问题。

    3.NSLook

    有点类似于@synchronized 保证多线程代码安全

     lock = [[NSLock alloc] init];
    
    [lock lock];
    
    代码块
    
    [lock unlock];    
    
    4.NSCondition

    条件锁,只有达到条件之后,才会执行锁操作

    BOOL canLock = [conditionLock tryLockWhenCondition:condition];
    
    5.NSRecursiveLock

    递归锁主要防止崩溃,一个代码块里多次加锁

    比如:自身调用自身加锁。

    下面介绍一下多线程中加锁:先贴几行代码:

    
    - (void)testLock{
        
        __block NSString *name = @"000";
        static NSString *staName = @"staticName";
        
        ///常规代码锁
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"线程A,准备好");
            name = @"11";
            @synchronized(name){
                NSLog(@"线程A lock, 请等待");
                [NSThread sleepForTimeInterval:5];
                name = @"111";
                staName = @"static111";
               
                //如果判断语句为false,报错
                NSCAssert([name isEqualToString:@"111"], @"前面的值错误了,不满足条件");
                NSLog(@"线程A 执行完毕  %@  %@",name,staName);
            }
            
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"线程B,准备好");
            name = @"22";
            @synchronized(name){
                NSLog(@"线程B lock, 请等待");
                [NSThread sleepForTimeInterval:2];
                name = @"222";
                staName = @"static222";
                NSLog(@"线程B 执行完毕  %@  %@",name,staName);
            }
        });
    }
    

    正常情况下,不加任何锁,那么线程A和线程B的执行顺序是随机的。
    加了线程锁以后,再测试调用一下:

    for (int i = 0; i<10; i++) {
            [self testLock];
            sleep(20);
        }
    


    结论:
    1.异步线程中加锁 可以转化异步线程同步线程,保证唯一性
    2.如果不加锁,那么A和B的执行顺序是随机的, AB内部的代码执行顺序也是随机的
    3.加锁的对象,必须保证唯一不会被随便改变。通常用数据库本身或者self来做加锁对象。单例最好。如果加锁,则AB的执行顺序虽然是随机的,但是遇到锁,B还是会等待A锁内执行完毕再执行B。
    注意:如果在A方法中对加锁的对象做出了修改,那么B方法中的加锁将失效。继而变成随机执行


    待更新。。。

    相关文章

      网友评论

          本文标题:多线程异步安全,安全锁的问题

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