Atomicity of atomic, is it absolute thread safety, not absolute thread safety? First, look at the code and print results
@property (atomic, assign) NSInteger intA; //There is an attribute of atomic, indicating that it is atomic - (void)viewDidLoad { [super viewDidLoad]; //Start the value of a thread to the 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); }); //Enable the value of a thread to the 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); }); }
The error analysis is: because the intA is decorated with atomic, it is thread safe. When + 1, only one thread will operate, so the final print result must be 2000.
Take a look at the print results
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
The final result is totally different from what we expected. Why?
Attention
In fact, it's OK that atomic is used. This only means that set method is atomic. The effect is similar to the following effect
//atomic means to lock the set method. When setting the value, only one thread will execute the set method - (void)setIntA:(NSInteger)intA{ [self.lock lock]; _intA = intA; [self.lock unlock]; }
Just lock the set method, and the self.intA = self.intA + 1 in our program; this part is not thread safe, and the subsequent + 1 operation is not thread safe, so in order to get the final result of 2000, you need to use the lock to lock self.intA = self.intA + 1, the code is as follows, here you can change the atomic modifier to nonatomic, the final modified code and printing The results are as follows:
@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); }); } //Print results 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
As for which lock to use, you can choose. Different locks have different execution efficiency