iOS多线程安全
参考网上文章做一个总结
先说说定义属性的关键字:
atomic和nonatomic
atomic是原子性,nonatomic是非原子性(换句话说就是atmoic线程安全、nonatomic非线程安全)因为但也仅仅是在调用getter、setter方法是原子安全,所以并不能只通过给属性设置atomic达到多线程安全,要达到线程安全还需要程序猿自己给代码块加锁实现。
iOS给代码加锁的方式有很多种,常用的有:
@synchronized(token)
NSLock
dispatch_semaphore_t
OSSpinLock
这几种锁都可以带来原子性,性能的损耗从上至下依次更小。
Y神建议是,在编写应用层代码的时候,除了OSSpinLock之外,哪个顺手用哪个。相较于这几个锁的性能差异,代码逻辑的正确性更为重要。而且这几者之间的性能差异对用户来说,绝大部分时候都感知不到。
当两条以上的线程对属性进行读写操作时,很可能会造成线程安全问题。就算用atomic修饰属性也于事无补。
例如:
@property (atomic, strong) NSString* stringA;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//thread A
for (int i = 0; i < 100000; i ++) {
if (i % 2 == 0) {
self.stringA = @"a very long string";
}
else {
self.stringA = @"string";
}
NSLog(@"Thread A: %@\n", self.stringA);
}
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//thread B
for (int i = 0; i < 100000; i ++) {
if (self.stringA.length >= 10) {
NSString* subStr = [self.stringA substringWithRange:NSMakeRange(0, 10)];
}
NSLog(@"Thread B: %@\n", self.stringA);
}
});
所以必须要给会造成线程安全的代码块加锁:
//thread A
[_lock lock];
for (int i = 0; i < 100000; i ++) {
if (i % 2 == 0) {
self.stringA = @“a very long string”;
}
else {
self.stringA = @“string”;
}
NSLog(@“Thread A: %@\n”, self.stringA);
}
[_lock unlock];
//thread B
[_lock lock];
if (self.stringA.length >= 10) {
NSString* subStr = [self.stringA substringWithRange:NSMakeRange(0, 10)];
}
[_lock unlock];