对nonatomic和atomic的一点看法

我们在声明一个属性的时候,经常性会把每个属性定义为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的一点看法)