關於IOS屬性atomic(原子性)的理解

NO IMAGE

拋開語言限制說說什麼是原子性:

原子性是指一個事物的操作是不可分割的,要麼都發生,要麼都不發生。

舉個栗子🌰:(摘自某位不願意透露姓名的大神

銀行的轉賬業務就是一個原子性的操作。
張三到銀行給李四轉賬1000元,張三卡里原來有2000元,李四卡里原來也有兩千元,那麼轉賬的步驟應該如下:

關於IOS屬性atomic(原子性)的理解

如果張三的錢扣完,銀行系統癱瘓了,怎麼辦呢?張三的1000塊錢會被會沒呢,當然不會。這時候你的錢會退回來。也就是說銀行的轉賬業務要麼成功張三(1000元)李四(3000元),要麼不發生張三(2000元)李四(2000元)。

那麼回到我們OC中:(這裡講的是我們的Objective-c)

看看我們的atomic和nonatomic,我們通常的理解是線程安全和非線程安全,我覺得這隻在語言層面上描述原子性造成的結果。

因為atomic描述的是屬性賦值,屬性賦值中還包含著很多其他操作,如訪問對象,賦值等等,natomic是保證這個賦值的整個過程的完整性,並且不受其他線程的干擾,要麼成功要麼失敗。

看個問題:為什麼說atomic有時候無法保證線程安全呢?

先說我的結論:
用atomic修飾後,這個屬性的setter、getter方法是線程安全的,但是對於整個對象來說不一定是線程安全的。

1.為什麼setter、getter方法是線程安全的?

因為在setter和getter賦值取值的時候添加了自旋鎖,不懂看這《oc中的線程鎖》

// getter
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
// ...
if (!atomic) return *slot;
// Atomic retain release world
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();
// ...
}
// setter
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
// ...
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;        
slotlock.unlock();
}
// ...
}

2.為什麼說atomic沒辦法保證整個對象的線程安全,這裡主要看一下網上主流的答案?

1.對於NSArray類型 @property(atomic)NSArray *array我們用atomic修飾,數組的添加和刪除並不是線程安全的,這是因為數組比較特殊,我們要分成兩部分考慮,一部分是&array也就是這個數組本身,另一部分是他所指向的內存部分。atomic限制的只是&array部分,對於它指向的對象沒有任何限制。
atomic表示,我TM也很冤啊!!!!

2.當線程A進行寫操作,這時其他線程的讀或者寫操作會因為該操作而等待。當A線程的寫操作結束後,B線程進行寫操作,然後當A線程需要讀操作時,卻獲得了在B線程中的值,這就破壞了線程安全,如果有線程C在A線程讀操作前release了該屬性,那麼還會導致程序崩潰。所以僅僅使用atomic並不會使得線程安全,我們還要為線程添加lock來確保線程的安全。
個人覺得這個就有點槓精的意味了,atomic還要管到你方法外面去了?????不過面試人家問你還要這麼答,要嚴謹!!,

個人理解有問題大家多多提出,討論中才能學習。

好文推薦:
《iOS atomic 對象是線程不安全的原因以及與 nonatomic 的區別》(這個名字很奇怪😄,說白了不安全是由OC對象的引用特性造成的,可以看下)
《事務四大特徵:原子性,一致性,隔離性和持久性(ACID)》

相關文章

SpringIoC容器初始化—Resource定位源碼分析

《YYModel源碼分析(二)NSObject+YYModel》

《YYModel源碼分析(一)YYClassInfo》

SDMemoryCache中的NSMapTable