1.atomic的作用?
用處一: 生成原子操作的getter和setter。
設(shè)置atomic之后,默認(rèn)生成的getter和setter方法執(zhí)行是原子的。也就是說(shuō),當(dāng)我們?cè)诰€程1執(zhí)行g(shù)etter方法的時(shí)候(創(chuàng)建調(diào)用棧,返回地址,出棧),線程B如果想執(zhí)行setter方法,必須先等getter方法完成才能執(zhí)行。舉個(gè)例子,在32位系統(tǒng)里,如果通過(guò)getter返回64位的double,地址總線寬度為32位,從內(nèi)存當(dāng)中讀取double的時(shí)候無(wú)法通過(guò)原子操作完成,如果不通過(guò)atomic加鎖,有可能會(huì)在讀取的中途在其他線程發(fā)生setter操作,從而出現(xiàn)異常值。如果出現(xiàn)這種異常值,就發(fā)生了多線程不安全。
用處二:設(shè)置Memory Barrier
對(duì)于Objective C的實(shí)現(xiàn)來(lái)說(shuō),幾乎所有的加鎖操作最后都會(huì)設(shè)置memory barrier,atomic本質(zhì)上是對(duì)getter,setter加了鎖,所以也會(huì)設(shè)置memory barrier。官方文檔表述如下:
Note: Most types of locks also incorporate a memory barrier to ensure that any preceding load and store instructions are completed before entering the critical section.
memory barrier有什么用處呢?
memory barrier能夠保證內(nèi)存操作的順序,按照我們代碼的書寫順序來(lái)。聽(tīng)起來(lái)有點(diǎn)不可思議,事實(shí)是編譯器會(huì)對(duì)我們的代碼做優(yōu)化,在它認(rèn)為合理的場(chǎng)景改變我們代碼最終翻譯成的機(jī)器指令順序。
2.atomic是線程安全?
不是,原因是atomic保證setter、getter的原子性,但是不保證對(duì)象在多個(gè)線程中是原子性操作(讀、寫是串行操作),所以atomic不保證對(duì)象的線程安全!
如何做到線程安全?
原子性、線程加鎖
線程安全和atomic沒(méi)有關(guān)系,這也是為什么我們?cè)谧龆嗑€程安全的時(shí)候,并不是通過(guò)給property加atomic關(guān)鍵字來(lái)保障安全,而是將property聲明為nonatomic(nonatomic沒(méi)有g(shù)etter,setter的鎖開(kāi)銷),然后自己加鎖。
線程安全的問(wèn)題不是給property加上atomic就能搞定的,atomic只能保證property的setter、getter方法原子性,不能保證代碼邏輯的原子性。
代碼的原子性需要我們自己加鎖,特別是對(duì)于集合NSArray,NSDictionary等操作要保證原子性,必須在讀、寫操作時(shí)分別上鎖,同時(shí)保證讀和寫的原子性才能保證多線程安全
參考:iOS多線程到底不安全在哪里?http://mrpeak.cn/blog/ios-thread-safety/