atomic是绝对安全的么?

2021-01-14  本文已影响0人  Amor瑾年v

atomic只能保证属性的存取是线程安全的,并不能保证整个对象是线程安全的。
首先看一下代码以及打印结果:

@property (atomic, assign) NSInteger intA;   //有一个atomic的属性,表示是原子的
 
 
- (void)viewDidLoad {
   [super viewDidLoad];
   //开启一个线程对intA的值+1
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       for (int i = 0;i < 1000;i ++){
           self.intA = self.intA + 1;
       }
       NSLog(@"intA : %ld",(long)self.intA);
   });
   
   //开启一个线程对intA的值+1
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       for (int i = 0;i < 1000;i ++){
           self.intA = self.intA + 1;
       }
       NSLog(@"intA : %ld",(long)self.intA);
   });   

错误的分析是:因为intA是atomic修饰的,所以是线程安全的,在+1的时候,只会有一个线程去操作,所以最终的打印结果必定有一个是2000。
结果:

2018-09-12 08:47:20.019123+0800 Test[1019:48584] intA : 1186
2018-09-12 08:47:20.019123+0800 Test[1019:48583] intA : 896

只是对set方法加锁,而我们程序里面的self.intA = self.intA + 1; 这一部分不是线程安全的,后面这个+1操作不是线程安全的,所以要想最终得到2000的结果,需要使用锁对self.intA = self.intA + 1加锁,代码如下,这里可以将atomic修饰词改为nonatomic,最终修改的代码以及打印结果如下

@property (nonatomic, assign) NSInteger intA;
- (void)viewDidLoad {
    [super viewDidLoad];
    self.lock = [[NSLock alloc] init];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0;i < 1000;i ++){
            [self.lock lock];
            self.intA = self.intA + 1;
            [self.lock unlock];
        }
        NSLog(@"intA : %ld",(long)self.intA);
    });
 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0;i < 1000;i ++){
            [self.lock lock];
            self.intA = self.intA + 1;
            [self.lock unlock];
        }
        NSLog(@"intA : %ld",(long)self.intA);
    });
 }
 
 
打印结果
2018-09-12 09:06:57.071829+0800 Test[2200:97290] intA : 1360
2018-09-12 09:06:57.071966+0800 Test[2200:97293] intA : 2000
上一篇 下一篇

猜你喜欢

热点阅读