任何時候探究一些原理都得從源碼抓起 objc_sync
關(guān)于@synchronized,
使用場景一:寫單例的時候,
使用場景二:在多線程的情況下,進行加鎖操作.
那么鎖是如何傳入@synchronized的對象關(guān)聯(lián)上的???????
如果傳入@synchronized的對象在@synchronized的block里面被釋放或者被賦值為nil會怎樣???????
@synchronized block 會變成objc_sync_enter 和 objc_sync_exit成對調(diào)用.??????
??????????????????
@synchronized結(jié)構(gòu)在工作時為傳入的對象分配了一個遞歸鎖.
遞歸鎖在被同一線程重復(fù)獲取時不會產(chǎn)生死鎖.你可以在這找到一個它工作原理的精巧案例.和NSRecursiveLock類似.
在objc-sync的源碼中,有一個結(jié)構(gòu)體 struct SyncData,包含了object 就是我們傳入的對象和一個關(guān)聯(lián)的recursive_mutex_t, 它就是那個跟object關(guān)聯(lián)在一起的鎖.每個SyncData也包含一個指向另一個SyncData對象的指針,叫nextData.所以可以把每個SyncData結(jié)構(gòu)體看做是鏈表中的一個元素.每個SyncData還包含一個threadCount,這個syncData對象中的鎖會被一些線程使用或等待,threadCount就是此時這些線程的數(shù)量.syncData結(jié)構(gòu)體會被緩存,threadCount= 0 代表這個syncData實例可以被復(fù)用.
Struct SyncList的定義 把SyncData當(dāng)做是鏈表中的節(jié)點.每個SyncList結(jié)構(gòu)體都有個指向SyncData節(jié)點鏈表頭部的指針,也有一個用于防止多個線程對此列表做并發(fā)修改的鎖.
sDataLists的聲明是一個SyncList結(jié)構(gòu)體數(shù)組,大小16.通過哈希算法將傳入對象映射到數(shù)組上的一個下標(biāo).??????
當(dāng)調(diào)用objc_sync_enter(obj)時,用obj內(nèi)存地址的哈希值查找合適的SyncData,將其上鎖.當(dāng)調(diào)用objc_sync_exit(obj),查找合適的SyncData將其解鎖 ??????
總結(jié):
1.當(dāng)調(diào)用synchronzied的每個對象,runtime都會為其分配一個遞歸鎖并存儲在哈希表中
2.如果在synchronzied內(nèi)部對象被釋放或為nil,會執(zhí)行類似objc_sync_nil的空方法
3.不要想synchronzied block 傳入nil , 如果為nil ,則將會從代碼中線程安全
最后怒竿,思考:如何自己實現(xiàn)synchronized鎖呢桃熄?邊看源碼邊敲尋找靈感
參考鏈接:https://bestswifter.com/ios-lock/