前言
atomic/nonatomic 是属性修饰符之一,atomic 代表原子性,nonatomic 代表非原子性;原子性是防止方法调用到一半其它操作再次进入该方法,导致出现异常情况。
atomic 和 nonatomic 区别以及实现
首先我们知道 atomic 代表原子性,nonatomic 代表非原子性;用这两个修饰符来修饰属性,区别主要在于属性的 getter/setter 方法:atomic 会对 setter 方法进行加锁,nonatomic 不会对 setter 方法加锁。
atomic 修饰的属性,在 setter 方法中使用 @synchronized
加锁来确保原子操作,但是 @synchronized
相比于其它类型的锁,性能是最低效的,因为除了加锁之外,额外还会设置异常处理机制,性能消耗较大。这里就是为什么平时开发中很少使用 atomic 来修饰属性。
atomic 与 nonatomic 在 getter/setter 方法区别如下:
//interface
@property(nonatomic,strong)UIImage *icon;//nonatomic
@property(strong)UIImage *icon1;//atomic
//set
-(void)setIcon:(UIImage *)icon
{
if(_icon != icon)
{
[_icon release];
_icon = [icon retain];
}
}
//set
-(void)setIcon1:(UIImage *)icon1
{
//同步代码块
@synchronized (self) {
if(_icon1 != icon1)
{
[_icon1 release];
_icon1 = [icon1 retain];
}
}
}
atomic 不保证线程安全
atomic 只会保证 setter/getter 方法是原子操作的,防止方法调用到一半其它操作再次进入该方法,导致出现异常情况。即原子性保证你访问的时候给你返回一个完好无损的对象,但是不会保证线程安全,这里有个经典的例子:
//如果线程 A 调了 getter,与此同时线程 B 、线程 C 都调了 setter——那最后线程 A get 到的值,有3种可能:可能是 B、C set 之前原始的值,也可能是 B set 的值,也可能是 C set 的值。同时,最终这个属性的值,可能是 B set 的值,也有可能是 C set 的值。所以atomic可并不能保证对象的线程安全。
iOS 几种锁的性能差异
前面提到了 @synchronized 比其它锁性能低,这里就简单说一下 iOS 中的不同锁的性能差异,常见的锁有:@synchronized、NSLock、pthread mutexes、OSSpinLock;这篇 @synchronized, NSLock, pthread, OSSpinLock showdown, done right 文章对几种锁进行了实验,得出:@synchronized 是最慢的,OSSpinLock 是最快的;
@synchronized 性能差的原因就是前面提到过的:除了加锁操作之外,还需要设置异常处理机制。NSLock 是对 pthread mutexes 的 Objective-C 封装;OSSpinLock 目前已经废弃,可以使用 os_unfair_lock()
来进行加锁。
总结
现在知道 atomic 是不能保证线程安全的,还简单了解了 iOS 几种锁的性能差异;在总结这个面试知识点时,主要涉及到了线程编程,看了官方 Threading Programming Guide 文档,本来我也写了翻译总结,但是发现了一篇非常优秀的总结:Threading Programming Guide(1),大家可以去看看。
里面有很多有趣的知识点,以后慢慢跟大家一起学习,例如:
- Idle-time Notification
- 如何创建进程
- 利用 Run Loop 进行跨线程之间通讯
- 分离式线程与非分离式线程的区别
- ....
参考文献
@synchronized, NSLock, pthread, OSSpinLock showdown, done right
网友评论