一、atomic与nonatomic的区别!
首先,先介绍一下atomic
和nonatomic
1.atomic
使用同步锁,原子性:
在该属性在调用getter
和setter
方法时,会加上自旋锁(osspinlock)
,
即在属性在调用getter
和setter
方法时,保证同一时刻只能有一个线程调用属性的读/写方
2.nonatomic
:不使用同步锁,非原子性:
在该属性在调用getter和setter方法时,不会加上自旋锁
,也就是线程并不安全
然后,再介绍一下atomic
和nonatomic
的申明方式
@property(nonatomic,strong) NSString *test;
@property (atomic,strong) NSString *test;
@property (strong) NSString *test;
代码中可以看到这样的书写方式,那么这三个代码有什么不同呢?
其实:
@property (atomic,strong) NSString *test;
@property (strong) NSString *test;
这两个代码完全是一样的结果,省略不写即默认为atomic
,而不是nonatomic
中间,我为什么强调atomic
属性申明时在调用getter
和setter
方法时会加上自旋锁(osspinlock)
并且是只能有一个线程调用属性的读/写方法,没有说线程是安全的
对于atomic
的属性,系统生成的 getter/setter
会保证 get、set
操作的完整性,不受其他线程影响。
比如,线程 A 的 getter
方法运行到一半,线程 B 调用了 setter:
那么线程 A 的 getter
还是能得到一个完好无损的对象。
如果有一个 atomic
的属性 "name"
,如果线程 A 调[self setName:@"A"]
,线程 B 调[self setName:@"B"]
,线程 C 调[self name]
,那么所有这些不同线程上的操作都将依次顺序执行——也就是说,如果一个线程正在执行 getter/setter
,其他线程就得等待。因此,属性 name
是读/写安全的。
但是,如果有另一个线程 D 同时在调[name release]
,那可能就会crash
,因为 release
不受 getter/setter
操作的限制。也就是说,这个属性只能说是读/写
安全的,但并不是线程安全
的,因为别的线程还能进行读写
之外的其他操作。线程安全
需要开发者自己来保证
最后为什么说nonatomic
线程并不安全
如果 name
属性是 nonatomic
的,那么上面例子里的所有线程 A、B、C、D 都可以同时执行,可能导致无法预料的结果。如果是atomic
的,那么 A、B、C 会串行,而 D 还是并行的。
其实苹果官方文档也有解释
还有自旋锁osspinlock
因为并不安全已经被苹果淘汰,替换成为自旋锁os_unfair_lock
,详情可以参考YY大神ibireme
不再安全的 OSSpinLock