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

我是繁星發表於2018-12-28

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

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

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

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

未命名檔案-12.png
如果張三的錢扣完,銀行系統癱瘓了,怎麼辦呢?張三的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)》

相關文章