摘抄蘋(píng)果官方文檔為
Atomic is the default: if you don’t type anything, your property is atomic. An atomic property is guaranteed that if you try to read from it, you will get back a valid value. It does not make any guarantees about what that value might be, but you will get back good data, not just junk memory. What this allows you to do is if you have multiple threads or multiple processes pointing at a single variable, one thread can read and another thread can write. If they hit at the same time, the reader thread is guaranteed to get one of the two values: either before the change or after the change. What atomic does not give you is any sort of guarantee about which of those values you might get. Atomic is really commonly confused with being thread-safe, and that is not correct. You need to guarantee your thread safety other ways. However, atomic will guarantee that if you try to read, you get back some kind of value.
nonatomic
On the flip side, non-atomic, as you can probably guess, just means, “don’t do that atomic stuff.” What you lose is that guarantee that you always get back something. If you try to read in the middle of a write, you could get back garbage data. But, on the other hand, you go a little bit faster. Because atomic properties have to do some magic to guarantee that you will get back a value, they are a bit slower. If it is a property that you are accessing a lot, you may want to drop down to nonatomic to make sure that you are not incurring that speed penalty.
設(shè)置成員變量的@property屬性時(shí),默認(rèn)為atomic,提供多線程安全。
在多線程環(huán)境下,原子操作是必要的,否則有可能引起錯(cuò)誤的結(jié)果。加了atomic,setter函數(shù)會(huì)變成下面這樣:
{lock}
if (property != newValue) {
[property release];
property = [newValue retain];
}
{unlock}
也就說(shuō)使用了atomic屬性?xún)?nèi)部會(huì)通過(guò)加鎖的機(jī)制來(lái)確保其get/set操作的準(zhǔn)確性,防止在寫(xiě)為完成的時(shí)候被另一個(gè)線程讀取,造成數(shù)據(jù)錯(cuò)誤,缺點(diǎn)也是明顯的在ios中加鎖是一個(gè)很消耗系統(tǒng)資源的操作。
所以我們使用的屬性大部分為nonatomic,原因就是使用atomic開(kāi)銷(xiāo)比較大,帶來(lái)性能問(wèn)題,而且使用atomic也不能保證對(duì)象多線程的安全,它只是只能保證你訪問(wèn)的時(shí)候給你返回一個(gè)完好無(wú)損的值而已。
例如:假設(shè)有一個(gè) atomic 的屬性 "name",如果線程 A 調(diào)[self setName:@"A"],線程 B 調(diào)[self setName:@"B"],線程 C 調(diào)[self name],那么所有這些不同線程上的操作都將依次順序執(zhí)行——也就是說(shuō),如果一個(gè)線程正在執(zhí)行 getter/setter,其他線程就得等待。因此,屬性 name 是讀/寫(xiě)安全的。
但是,如果有另一個(gè)線程 D 同時(shí)在調(diào)[name release],那可能就會(huì)crash,因?yàn)?release 不受 getter/setter 操作的限制。也就是說(shuō),這個(gè)屬性只能說(shuō)是讀/寫(xiě)安全的,但并不是線程安全的,因?yàn)閯e的線程還能進(jìn)行讀寫(xiě)之外的其他操作。線程安全需要開(kāi)發(fā)者自己來(lái)保證。
如果 name 屬性是 nonatomic 的,那么上面例子里的所有線程 A、B、C、D 都可以同時(shí)執(zhí)行,可能導(dǎo)致無(wú)法預(yù)料的結(jié)果。如果是 atomic 的,那么 A、B、C 會(huì)串行,而 D 還是并行的。
我們可以認(rèn)為atomic只對(duì)一個(gè)屬性的getter/setter是安全的,其它的線程安全是無(wú)法保證的。
現(xiàn)在總結(jié)一下nonatomic與atomic的區(qū)別:
atomic:
系統(tǒng)默認(rèn)
會(huì)保證 CPU 能在別的線程來(lái)訪問(wèn)這個(gè)屬性之前,先執(zhí)行完當(dāng)前流程
性能低,速度慢
atomic 對(duì)象的getter/setter方法實(shí)現(xiàn):
-
(void)setCurrentImage:(UIImage *)currentImage
{
@synchronized(self) {
if (_currentImage != currentImage) {
[_currentImage release];
_currentImage = [currentImage retain];}}
} (UIImage *)currentImage
{
@synchronized(self) {
return _currentImage;
}
}
nonatomic:
不是默認(rèn)的
速度快
線程不安全的
nonatomic 對(duì)象的getter/setter方法實(shí)現(xiàn):-
(void)setCurrentImage:(UIImage *)currentImage
{
if (_currentImage != currentImage) {
[_currentImage release];
_currentImage = [currentImage retain];}
} (UIImage *)currentImage
{
return _currentImage;
}