iOS多線程可能形成共享資源的競爭,使用鎖能夠很好的解決這一問題,iOS的鎖有不少種,從性能上看@synchronized
彷佛沒啥競爭力,來自# 再也不安全的 OSSpinLockios
可是咱們爲何還要用這廝呢,由於用起來簡單啊!!!!git
@synchronized (person) {
//do something
}
複製代碼
打開always show disassembly
運行代碼github
經過objc_retain和objc_release
能夠看到@synchronized
和對象強引用,驗證一下數組
int main(int argc, char * argv[]) {
JPerson *person = [[JPerson alloc] init];
NSLog(@"--%lu",CFGetRetainCount((__bridge CFTypeRef)(person)));
@synchronized (person) {
NSLog(@"%@",person);
NSLog(@"--%lu",CFGetRetainCount((__bridge CFTypeRef)(person)));
}
NSLog(@"--%lu",CFGetRetainCount((__bridge CFTypeRef)(person)));
return 0;
}
複製代碼
在objc4-781.2搜索objc_sync_enter
緩存
obc
爲空就執行objc_sync_nil
,進一步查看發現什麼也沒執行obc
不爲空就獲取對象SyncData* data
的data->mutext
加鎖這裏的重點應該在SyncData
和id2data
sass
這是一個單鏈表節點安全
這裏代碼比較多,關注點太多容易分散精力,咱們只重點關注非緩存的狀況系統是如何處理的markdown
點進去看看多線程
這時的重點來到了StripedMap<SyncList>
app
能夠看到StripedMap
是一個數組結構,用來存儲SyncList
obj
對應的SyncData
跳轉到done
執行obj
對應的SyncData
可是找到了空節點,那麼將obj
賦值給空節點SyncList
的頭部id2data
簡單總結如圖:有一個全局的長度爲8的數組StripedMap
(這個數組是不須要擴容的),數組裏存儲的是SyncList
指針,SyncList
裏面存儲SyncData
節點指針,SyncData
節點存儲指向下一個SyncData
節點指針,造成單鏈表結構。
爲了提高訪問速度,蘋果設計了兩級緩存TLS
和SyncCache
,下面咱們具體看一下
TLS能夠認爲是線程私有存儲空間
tls_get_direct
:根據key從TLS字典讀取值tls_set_direct
:根據key、value存儲到TLS字典能夠看到若是沒有從快速緩存TLS中查找到結果,done後面代碼執行也會存儲一份進去
操做很簡單,就是遍歷數組匹配object
SyncCacheItem
結構體包含
SyncData
指針lockCount
SyncCache
結構體包含
SyncCacheItem
的數組list
allocated
used
_objc_pthread_data結構
從這裏咱們看到了兩個熟悉的身影tls_get
和tls_set
,建立的_objc_pthread_data
結構體也是存儲在了TLS中
只作了一個解鎖操做,建立的SyncData
並無刪除
咱們是經過傳入的obj
地址做爲標識來操做SyncData
的,若是obj
地址發生變化那是會出現問題的,例如
簡單理解假如t一、t2兩個線程要訪問person
,person
初始值爲a0
person
地址爲a0,加鎖person
地址也爲a0,等待解鎖person
地址變爲a1,a0被釋放,解鎖,t2可訪問person
地址變爲a2,a0又被釋放,重複釋放形成崩潰因此咱們通常傳入對屬性所在對象的self
,這樣雖然必定程度上保證了線程安全,可是影響範圍擴大