一、atomic與nonatomic的區(qū)別!
首先,先介紹一下atomic
和nonatomic
1.atomic
使用同步鎖,原子性:
在該屬性在調(diào)用getter
和setter
方法時,會加上自旋鎖(osspinlock)
,
即在屬性在調(diào)用getter
和setter
方法時,保證同一時刻只能有一個線程調(diào)用屬性的讀/寫方
2.nonatomic
:不使用同步鎖,非原子性:
在該屬性在調(diào)用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;
這兩個代碼完全是一樣的結(jié)果,省略不寫即默認為atomic
,而不是nonatomic
中間,我為什么強調(diào)atomic
屬性申明時在調(diào)用getter
和setter
方法時會加上自旋鎖(osspinlock)
并且是只能有一個線程調(diào)用屬性的讀/寫方法,沒有說線程是安全的
對于atomic
的屬性,系統(tǒng)生成的 getter/setter
會保證 get、set
操作的完整性,不受其他線程影響。
比如,線程 A 的 getter
方法運行到一半,線程 B 調(diào)用了 setter:
那么線程 A 的 getter
還是能得到一個完好無損的對象。
如果有一個 atomic
的屬性 "name"
,如果線程 A 調(diào)[self setName:@"A"]
,線程 B 調(diào)[self setName:@"B"]
,線程 C 調(diào)[self name]
,那么所有這些不同線程上的操作都將依次順序執(zhí)行——也就是說,如果一個線程正在執(zhí)行 getter/setter
,其他線程就得等待。因此,屬性 name
是讀/寫安全的。
但是,如果有另一個線程 D 同時在調(diào)[name release]
,那可能就會crash
,因為 release
不受 getter/setter
操作的限制。也就是說,這個屬性只能說是讀/寫
安全的,但并不是線程安全
的,因為別的線程還能進行讀寫
之外的其他操作。線程安全
需要開發(fā)者自己來保證
最后為什么說nonatomic
線程并不安全
如果 name
屬性是 nonatomic
的,那么上面例子里的所有線程 A、B、C、D 都可以同時執(zhí)行,可能導(dǎo)致無法預(yù)料的結(jié)果。如果是atomic
的,那么 A、B、C 會串行,而 D 還是并行的。
其實蘋果官方文檔也有解釋
還有自旋鎖osspinlock
因為并不安全已經(jīng)被蘋果淘汰,替換成為自旋鎖os_unfair_lock
,詳情可以參考YY大神ibireme
不再安全的 OSSpinLock