美文网首页
对nonatomic和atomic的一点看法

对nonatomic和atomic的一点看法

作者: 程序狗 | 来源:发表于2018-05-22 16:50 被阅读8次

    我们在声明一个属性的时候,经常性会把每个属性定义为nonatomic(非原子性),很少用atomic。原因就是属性定义为atomic也不能保证线程安全,而且atomic加了同步锁,性能较nonatomic慢。
    此时问题就来了,原子性是什么呢, 设置了之后在哪里加了锁?
    实际上,如果一个属性定义为atomic,那么它的setter和getter会通过锁的方式来确保两个方法完整执行。也就是说,如果两个线程同时读取一个属性,那么无论何时,都能读取有效的属性值。

    @interface TestObj : NSObject
    @property (atomic, copy) NSString *firstName;
    
      TestObj *obj = [[TestObj alloc]init];
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //          NSLog(@"obj1 first: %@",obj.firstName);
            obj.firstName = @"zhu";
            NSLog(@"obj1: %@",obj.firstName);
          
            
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //         NSLog(@"obj2 first: %@",obj.firstName);
    //        obj.firstName = @"xixi";
          NSLog(@"obj2: %@",obj.firstName);
      
            
        });
    
    打印信息
    2018-05-22 16:17:01.658839+0800 testIndex[727:19821729] obj2: zhu
    2018-05-22 16:17:01.658839+0800 testIndex[727:19821728] obj1: zhu
    

    假设不加锁的话

    @interface TestObj : NSObject
    
    @property (nonatomic, copy) NSString *firstName;
    
    

    那么上面那段代码可能就会出现

    2018-05-22 16:18:55.476249+0800 testIndex[793:19841361] obj2: (null)
    2018-05-22 16:18:55.476273+0800 testIndex[793:19841362] obj1: zhu
    

    那么atomic就是可靠的吗,nonatomic是非原子性的,本来就是非线程安全的,那么我们为啥还要用nonatomic。
    其实atomic和nonatomic也就是setter和getter上操作的不同
    nonatomic

    - (void)setFirstName:(NSString *)firstName
    {
        if (_firstName != firstName) {
            [_firstName release];
            _firstName = [firstName retain];
        }
    }
    - (NSString *)firstName
    {
        return _firstName;
    }
    

    atomic的实现

    - (void)setFirstName:(NSString *)firstName
    {
     @synchronized(self) {
        if (_firstName != firstName) {
            [_firstName release];
            _firstName = [firstName retain];
        }
      }
    }
    - (NSString *)firstName
    {
      @synchronized(self) {
        return _firstName;
      }
    }
    

    atomic时,虽然对属性的读和写是原子性的,但是仍可能出现线程错误。假设线程A对firstName进行写操作,但同时线程B也进行写操作,虽然两个写操作是依次进行的,但是如果线程A如果有读操作,可能执行获取到的firstName并不是线程A写的数据,这就不是线程安全了。
    不加lock

       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //        [lock lock];
            obj.firstName = @"zhu";
            NSLog(@"obj1: %@",obj.firstName);
    //        [lock unlock];
            
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //  [lock lock];
            obj.firstName = @"xixi";
          NSLog(@"obj2: %@",obj.firstName);
    //    [lock unlock];
            
        });
    

    输出可能是

    2018-05-22 16:48:15.663898+0800 testIndex[1157:20091711] obj1: xixi
    2018-05-22 16:48:15.663898+0800 testIndex[1157:20091710] obj2: xixi
    

    加了锁之后

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [lock lock];
            obj.firstName = @"zhu";
            NSLog(@"obj1: %@",obj.firstName);
            [lock unlock];
            
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [lock lock];
            obj.firstName = @"xixi";
            NSLog(@"obj2: %@",obj.firstName);
            [lock unlock];
            
        });
    

    输出是

    2018-05-22 16:49:04.088074+0800 testIndex[1185:20099838] obj1: zhu
    2018-05-22 16:49:04.088232+0800 testIndex[1185:20099837] obj2: xixi
    

    其实证明了我们使用了atomic还不能保证线程安全性,又用了同步锁,耗费性能,所以我们通过nonatomic关键字居多,线程安全通过加lock保证。

    相关文章

      网友评论

          本文标题:对nonatomic和atomic的一点看法

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