自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

iOS多線程遞歸鎖:@synchronized底層原理探究

原創(chuàng) 精選
移動(dòng)開發(fā) iOS
在iOS開發(fā)中,有一種簡單而強(qiáng)大的同步機(jī)制——@synchronized關(guān)鍵字,它通過保護(hù)臨界區(qū)代碼和支持遞歸鎖,確保多線程環(huán)境中的線程安全。本文將深入解析其底層實(shí)現(xiàn)原理。

作者 | 張璇、張凱

審校 | 重樓

一、背景與意義

在系統(tǒng)應(yīng)用開發(fā)中,隨著應(yīng)用程序復(fù)雜度的增加,多線程編程成為了提升用戶體驗(yàn)和應(yīng)用性能的關(guān)鍵技術(shù)之一,線程同步占據(jù)著舉足輕重的地位。鑒于iOS應(yīng)用程序普遍涉及多任務(wù)處理和并發(fā)操作,確保線程安全成為一項(xiàng)至關(guān)重要的任務(wù)。Objective-C語言為此提供了一種高效且可靠的同步機(jī)制,即@synchronized關(guān)鍵字。這一機(jī)制通過標(biāo)記特定代碼段為臨界區(qū),確保了同一時(shí)刻僅有一個(gè)線程能夠執(zhí)行該代碼塊,從而有效保護(hù)了數(shù)據(jù)的一致性和完整性。

此外,@synchronized關(guān)鍵字在多線程環(huán)境中還具備遞歸鎖定的能力。這意味著同一線程可以多次獲取同一把鎖,而不會(huì)導(dǎo)致死鎖的產(chǎn)生,極大地提升了遞歸調(diào)用的安全性和可行性。

二、關(guān)鍵技術(shù)

在iOS多線程環(huán)境中,@synchronized關(guān)鍵字是實(shí)現(xiàn)線程同步和遞歸鎖定的關(guān)鍵技術(shù)。其內(nèi)部實(shí)現(xiàn)原理基于Objective-C的運(yùn)行時(shí)(Runtime)和底層的鎖機(jī)制。

首先,@synchronized關(guān)鍵字在編譯時(shí)會(huì)被轉(zhuǎn)換成Objective-C運(yùn)行時(shí)庫中的一個(gè)函數(shù)調(diào)用,即objc_sync_enter和objc_sync_exit。這兩個(gè)函數(shù)分別用于獲取和釋放鎖。當(dāng)線程嘗試進(jìn)入@synchronized代碼塊時(shí),objc_sync_enter函數(shù)會(huì)被調(diào)用,并嘗試獲取與給定對(duì)象相關(guān)聯(lián)的鎖。如果鎖已經(jīng)被其他線程持有,則當(dāng)前線程將被阻塞,直到鎖被釋放。如果鎖成功獲取,則線程可以安全地執(zhí)行@synchronized代碼塊中的代碼。

其次,@synchronized關(guān)鍵字的遞歸鎖定能力是通過在運(yùn)行時(shí)維護(hù)一個(gè)線程到鎖計(jì)數(shù)器的映射來實(shí)現(xiàn)的。當(dāng)同一線程多次進(jìn)入同一個(gè)@synchronized代碼塊時(shí),鎖計(jì)數(shù)器會(huì)遞增,而不是重新獲取鎖。這樣,即使線程多次進(jìn)入臨界區(qū),也不會(huì)導(dǎo)致死鎖。當(dāng)線程離開@synchronized代碼塊時(shí),鎖計(jì)數(shù)器會(huì)遞減,直到計(jì)數(shù)器歸零,此時(shí)鎖才會(huì)被釋放,允許其他線程進(jìn)入臨界區(qū)。

2.1 @synchronized的源碼入口

首先,通過一個(gè)demo來了解下@synchronized的具體結(jié)構(gòu):

圖1 demo Objective-C語言版本示例圖1 demo Objective-C語言版本示例

在xcode中,可以通過clang -rewrit-objc命令,將上述的demo代碼重寫為C++代碼,這里將關(guān)鍵代碼提取如下:

圖2 demo C++語言版本示例圖2 demo C++語言版本示例

顯然,從給定信息中可以明確,_sync_exit()函數(shù)觸發(fā)了_SYNC_EXIT的構(gòu)造過程,而 ~_SYNC_EXIT是_SYNC_EXIT的析構(gòu)函數(shù)。從根本上講,@synchronized指令的底層實(shí)現(xiàn)依賴于對(duì)objc_sync_enter和objc_sync_exit這兩個(gè)函數(shù)的調(diào)用。接下來,我們將深入解析 objc_sync_enter 和 objc_sync_exit的具體實(shí)現(xiàn)方式。

2.2、objc_sync_enter 和 objc_sync_exit函數(shù)實(shí)現(xiàn)

objc_sync_enter和objc_sync_exit是 Objective-C 運(yùn)行時(shí)庫中用于處理同步鎖的關(guān)鍵函數(shù)。這兩個(gè)函數(shù)通過底層的鎖機(jī)制(如互斥鎖或自旋鎖)來確保在同一時(shí)刻,只有一個(gè)線程能夠執(zhí)行特定的代碼塊。下面,我們將詳細(xì)解析這兩個(gè)函數(shù)的實(shí)現(xiàn)方式及其背后的原理。

2.2.1 objc_sync_enter 函數(shù)的實(shí)現(xiàn)

objc_sync_enter函數(shù)的主要作用是嘗試獲取與給定對(duì)象相關(guān)聯(lián)的鎖。如果鎖已被其他線程持有,則當(dāng)前線程將被阻塞,直到鎖被釋放。這個(gè)函數(shù)的實(shí)現(xiàn)通常包括以下幾個(gè)步驟:

1. 計(jì)算鎖對(duì)象的哈希值:首先,根據(jù)傳入的對(duì)象(通常是作為@synchronized語句中鎖的唯一標(biāo)識(shí)符),計(jì)算出一個(gè)哈希值。這個(gè)哈希值用于在內(nèi)部的數(shù)據(jù)結(jié)構(gòu)中快速定位到對(duì)應(yīng)的鎖對(duì)象。

2.查找或創(chuàng)建鎖對(duì)象:在內(nèi)部的數(shù)據(jù)結(jié)構(gòu)中(如哈希表或鏈表),根據(jù)計(jì)算出的哈希值查找是否存在對(duì)應(yīng)的鎖對(duì)象。如果不存在,則創(chuàng)建一個(gè)新的鎖對(duì)象并插入到數(shù)據(jù)結(jié)構(gòu)中。這個(gè)鎖對(duì)象可能是一個(gè)封裝了互斥鎖或自旋鎖等底層同步機(jī)制的結(jié)構(gòu)體。

3. 嘗試獲取鎖:使用找到的鎖對(duì)象,嘗試獲取鎖。這通常涉及到底層同步機(jī)制的調(diào)用,如調(diào)用互斥鎖的lock方法或自旋鎖的相關(guān)操作。如果鎖已被其他線程持有,則當(dāng)前線程將被阻塞。

4.記錄線程與鎖的關(guān)系:為了支持遞歸鎖定,Objective-C 運(yùn)行時(shí)還需要記錄哪些線程已經(jīng)持有了哪些鎖,以及持有鎖的次數(shù)。這通常是通過一個(gè)線程到鎖計(jì)數(shù)器的映射來實(shí)現(xiàn)的。

圖3 objc_sync_enter函數(shù)源碼圖3 objc_sync_enter函數(shù)源碼

2.2.2 objc_sync_exit 函數(shù)的實(shí)現(xiàn)

objc_sync_exit函數(shù)的主要作用是釋放之前通過objc_sync_enter獲取的鎖。這個(gè)函數(shù)的實(shí)現(xiàn)通常包括以下幾個(gè)步驟:

1. 計(jì)算鎖對(duì)象的哈希值:與objc_sync_enter相同,首先根據(jù)傳入的對(duì)象計(jì)算哈希值,以找到對(duì)應(yīng)的鎖對(duì)象。

2. 查找鎖對(duì)象:在內(nèi)部的數(shù)據(jù)結(jié)構(gòu)中查找對(duì)應(yīng)的鎖對(duì)象。

3. 釋放鎖:使用找到的鎖對(duì)象,調(diào)用其釋放鎖的方法(如互斥鎖的unlock方法)。這將允許其他被阻塞的線程進(jìn)入臨界區(qū)。

4. 更新線程與鎖的關(guān)系:如果當(dāng)前線程是最后一次釋放該鎖(即鎖計(jì)數(shù)器減至零),則從線程到鎖計(jì)數(shù)器的映射中移除該線程的記錄。這確保了遞歸鎖定的正確性。

圖4 objc_sync_exit函數(shù)源碼圖4 objc_sync_exit函數(shù)源碼

2.3 總結(jié)

從深入探索objc_sync_enter和objc_sync_exit兩個(gè)函數(shù)的源代碼中,我們可以清晰地看到這兩個(gè)函數(shù)在同步機(jī)制中的核心作用。它們通過巧妙地利用互斥鎖data->mutex,確保了線程安全地進(jìn)入和退出同步塊。這種機(jī)制在并發(fā)編程中至關(guān)重要,能夠防止多個(gè)線程同時(shí)訪問共享資源,從而避免了數(shù)據(jù)競爭和不一致性的風(fēng)險(xiǎn)。

進(jìn)一步地,我們發(fā)現(xiàn)data這個(gè)變量實(shí)際上是指向一個(gè)SyncData類型實(shí)例對(duì)象的指針。在這里,SyncData扮演了至關(guān)重要的角色,它封裝了與同步操作相關(guān)的所有必要信息,包括互斥鎖、同步狀態(tài)等。通過精心設(shè)計(jì)的SyncData結(jié)構(gòu)體,我們能夠更加靈活地管理和控制同步資源的訪問,確保程序在不同線程之間的協(xié)調(diào)運(yùn)行。

與此同時(shí),id2data這一組件也引起了我們的關(guān)注。從名字上推測(cè),它似乎是一個(gè)用于將某種標(biāo)識(shí)符(如對(duì)象ID)映射到對(duì)應(yīng)SyncData實(shí)例的函數(shù)或方法。在并發(fā)編程中,這樣的映射關(guān)系對(duì)于快速定位和管理同步資源至關(guān)重要。通過id2data,我們可以根據(jù)傳入的obj(可能是某個(gè)對(duì)象的唯一標(biāo)識(shí)符)快速地查找到對(duì)應(yīng)的data(即該對(duì)象的同步數(shù)據(jù))。這種映射機(jī)制大大提高了同步操作的效率和準(zhǔn)確性,為程序的并發(fā)執(zhí)行提供了強(qiáng)有力的支持。

為了更深入地理解SyncData結(jié)構(gòu)體和id2data的具體實(shí)現(xiàn),我們將在接下來的第三小節(jié)中詳細(xì)探討SyncData的結(jié)構(gòu)和成員變量,以及它在同步機(jī)制中的具體應(yīng)用。同時(shí),在第四小節(jié)中,我們將解析id2data的實(shí)現(xiàn)細(xì)節(jié),包括它如何接收輸入?yún)?shù)、進(jìn)行映射查找以及返回對(duì)應(yīng)的SyncData實(shí)例。通過對(duì)這些核心組件的深入理解,我們將能夠更好地掌握Objective-C的同步機(jī)制,并在實(shí)際開發(fā)中靈活運(yùn)用。

三、SyncData結(jié)構(gòu)體介紹與解析

首先,讓我們對(duì)SyncData結(jié)構(gòu)體的實(shí)現(xiàn)進(jìn)行了解:

圖5 SyncData基本結(jié)構(gòu)體圖5 SyncData基本結(jié)構(gòu)體

從這段源碼中可以看到SyncData的基本結(jié)構(gòu),本質(zhì)上是存放了一個(gè)傳入對(duì)象obj的單向鏈表、一把遞歸鎖、以及使用的線程數(shù)量。可以從下面的這段源碼中看一下這把遞歸鎖。這把遞歸鎖本質(zhì)上是基于os_unfair_lock的封裝。這里補(bǔ)充下:os_unfair_lock是iOS中的一把互斥鎖。在之前的版本中recursive_mutex_t是由pthread_mutex_t來進(jìn)行封裝的,因此這里只需要將其理解成一把互斥鎖即可。

圖6 recursive_mutex_t基本結(jié)構(gòu)圖6 recursive_mutex_t基本結(jié)構(gòu)

四、id2data的底層實(shí)現(xiàn)的分析與研究

在正式深入分析id2data的詳盡細(xì)節(jié)之際,為了構(gòu)建一個(gè)更為明晰的認(rèn)知框架,本文將首先對(duì)所涉及的數(shù)據(jù)結(jié)構(gòu)進(jìn)行一次宏觀層面的梳理與整體性闡述。此舉旨在為后續(xù)針對(duì)id2data的深入探討奠定堅(jiān)實(shí)的背景知識(shí)基礎(chǔ),確保各位讀者能夠依托這一穩(wěn)固的基石,更加精準(zhǔn)地把握相關(guān)概念與邏輯脈絡(luò)。

4.1 SyncCache的底層實(shí)現(xiàn)邏輯

圖7 SyncCache基本結(jié)構(gòu)圖7 SyncCache基本結(jié)構(gòu)

可以明顯地觀察到,SyncCache容器中存儲(chǔ)的是SyncData類型的數(shù)據(jù)。SyncData這個(gè)結(jié)構(gòu)體在文章的第三部分已經(jīng)進(jìn)行了詳細(xì)的說明,因此在這里就不再重復(fù)解釋了。實(shí)際上,從這個(gè)細(xì)節(jié)上我們可以推測(cè)出,SyncCache似乎是一個(gè)專門設(shè)計(jì)用來存儲(chǔ)含有SyncData的SyncCacheItem對(duì)象的緩存機(jī)制。從這個(gè)角度來看,SyncCache的功能和用途變得非常明顯,它就是一個(gè)用來加快數(shù)據(jù)訪問速度的臨時(shí)存儲(chǔ)區(qū)域,當(dāng)需要訪問數(shù)據(jù)時(shí),可以直接從SyncCache中獲取,從而提高程序的運(yùn)行效率。同時(shí),這也體現(xiàn)了設(shè)計(jì)者對(duì)于數(shù)據(jù)存儲(chǔ)和讀取效率的重視,通過引入緩存機(jī)制,使得頻繁訪問的數(shù)據(jù)能夠快速獲取,從而提升整體的性能表現(xiàn)。

4.2 Fast Cache(快速緩存)

圖8 快速存儲(chǔ)內(nèi)部存儲(chǔ)結(jié)構(gòu)圖8 快速存儲(chǔ)內(nèi)部存儲(chǔ)結(jié)構(gòu)

這里的快速緩存,其實(shí)和SyncCache在本質(zhì)上是非常相似的,它們都是一種用于提升數(shù)據(jù)讀取速度的緩存機(jī)制。二者的主要區(qū)別在于,SyncCache是將數(shù)據(jù)存儲(chǔ)在一個(gè)列表中,而快速緩存則只是存儲(chǔ)了單個(gè)的SyncCacheItem。每個(gè)Item都通過兩個(gè)關(guān)鍵的Key來獲取其對(duì)應(yīng)的data和lockCount。這種設(shè)計(jì)使得快速緩存能夠更快地讀取數(shù)據(jù),因?yàn)樗恍枰闅v整個(gè)列表,而是直接通過Key來獲取數(shù)據(jù)。同時(shí),這也使得快速緩存的存儲(chǔ)空間更加節(jié)省,因?yàn)樗恍枰獮橐粋€(gè)列表分配大量的內(nèi)存空間。

4.3 sDataLists的底層實(shí)現(xiàn)邏輯

sDataLists是一個(gè)全局性的靜態(tài)變量,意味著在整個(gè)應(yīng)用程序中,它只能存在一個(gè)實(shí)例。在這個(gè)全局變量中,包含了一個(gè)名為SyncList的特殊列表。這個(gè)SyncList列表在程序中具有獨(dú)特的地位,它負(fù)責(zé)管理和同步所有需要共享和更新狀態(tài)的數(shù)據(jù)。由于它是靜態(tài)的,所以無論在程序的哪個(gè)部分,只要需要訪問sDataLists,都能直接通過它的名稱來引用它,而不需要先創(chuàng)建一個(gè)局部變量。這種設(shè)計(jì)使得數(shù)據(jù)的管理和同步變得更加高效和便捷。

圖9 sDataLists存儲(chǔ)結(jié)構(gòu)圖9 sDataLists存儲(chǔ)結(jié)構(gòu)

圖10 SyncList基本結(jié)構(gòu)圖10 SyncList基本結(jié)構(gòu)

4.4 StripedMap的設(shè)計(jì)與實(shí)現(xiàn)

在深入剖析sDataLists的源代碼架構(gòu)時(shí),我們可明確辨識(shí)出sDataLists本質(zhì)上遵循哈希表的數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)。這一精心策劃的架構(gòu)背后,蘊(yùn)含著深遠(yuǎn)的目的與周詳?shù)目剂?。哈希表作為一種高效的數(shù)據(jù)組織方式,其核心優(yōu)勢(shì)在于顯著提升數(shù)據(jù)檢索的速度與效率。然而,在當(dāng)前的實(shí)現(xiàn)框架中,哈希表所承載的功能與角色遠(yuǎn)超于此單一范疇。

若我們摒棄采用StripedMap的策略,系統(tǒng)將不得不依賴單一的全局SyncList實(shí)例來統(tǒng)籌所有對(duì)象的鎖定與解鎖流程。此設(shè)計(jì)方案雖簡潔,卻潛藏著顯著的性能瓶頸。具體而言,每當(dāng)有任一對(duì)象嘗試訪問或修改該哈希表時(shí),其操作將被迫暫停,直至其他所有對(duì)象完成其解鎖操作,方可繼續(xù)執(zhí)行。此類串行化的處理方式,無疑將大幅度加劇內(nèi)存的占用情況,對(duì)系統(tǒng)整體性能構(gòu)成不利影響。

StripedMap的引入,為現(xiàn)存問題提供了有效的解決方案。其核心價(jià)值體現(xiàn)在對(duì)單一的SyncList實(shí)施分片處理,這一機(jī)制確保了多個(gè)對(duì)象能夠并行且獨(dú)立地操作不同的SyncList實(shí)例。通過StripedMap預(yù)先配置并管理一定數(shù)量的SyncList,并在實(shí)際調(diào)用時(shí)采取均衡分配的策略,系統(tǒng)得以顯著提升其并發(fā)處理能力。具體而言,每個(gè)對(duì)象在執(zhí)行加鎖操作時(shí),均能夠自主選擇一個(gè)獨(dú)立的SyncList進(jìn)行操作,從而成功規(guī)避了全局鎖可能引發(fā)的性能瓶頸問題。

4.5 TLS(Thread Local Storage)

TLS就是線程局部存儲(chǔ),是操作系統(tǒng)為線程單獨(dú)提供的私有空間,能存儲(chǔ)只屬于當(dāng)前線程的一些數(shù)據(jù)。

TLS,即線程局部存儲(chǔ),是操作系統(tǒng)提供的一種機(jī)制,為每個(gè)線程單獨(dú)分配一塊私有內(nèi)存空間,用于存儲(chǔ)只屬于該線程的數(shù)據(jù)。由于線程是操作系統(tǒng)進(jìn)行任務(wù)調(diào)度和資源分配的最小單位,因此TLS可以確保每個(gè)線程擁有獨(dú)立的存儲(chǔ)空間,避免了線程之間的數(shù)據(jù)干擾和沖突,提高了程序的并發(fā)性和穩(wěn)定性。

在多線程程序中,每個(gè)線程可能會(huì)訪問共享資源,如全局變量或共享內(nèi)存區(qū)域,這會(huì)導(dǎo)致數(shù)據(jù)競爭和競態(tài)條件,從而影響程序的正確性和可靠性。為了解決這個(gè)問題,開發(fā)者通常需要使用同步機(jī)制,如互斥鎖、信號(hào)量等,來保護(hù)共享資源的訪問。但是這些同步機(jī)制會(huì)帶來額外的開銷,降低程序的性能。而使用TLS,可以將一些需要頻繁訪問且不涉及共享資源的數(shù)據(jù)存儲(chǔ)在當(dāng)前線程的私有空間中,避免了同步機(jī)制的使用,提高了程序的運(yùn)行效率和性能。

TLS的使用需要開發(fā)者在編寫程序時(shí)進(jìn)行適當(dāng)?shù)穆暶骱统跏蓟?以確保每個(gè)線程都能夠正確地訪問其私有空間中的數(shù)據(jù)。同時(shí),由于TLS是操作系統(tǒng)提供的一種機(jī)制,其具體實(shí)現(xiàn)和接口可能會(huì)因操作系統(tǒng)的不同而有所差異,因此開發(fā)者需要根據(jù)具體的操作系統(tǒng)和編譯器環(huán)境進(jìn)行相應(yīng)的適配和調(diào)整。

4.6 id2Data的實(shí)現(xiàn)解析與研究

在探討我們當(dāng)前的議題,現(xiàn)轉(zhuǎn)入id2Data的具體實(shí)現(xiàn)細(xì)節(jié)。鑒于源碼存在一定程度的冗余性,以下將依據(jù)4.6.1至4.6.4小節(jié)進(jìn)行逐一解析。首先,系統(tǒng)將依據(jù)傳入的obj參數(shù)定位并檢索鎖及鏈表的起始節(jié)點(diǎn)。

圖11 id2Data基本結(jié)構(gòu)之入?yún)? title=圖11 id2Data基本結(jié)構(gòu)之入?yún)?/span>

4.6.1 FastCache快速查找

在每個(gè)線程的線程局部存儲(chǔ)(TLS)中,都會(huì)部署一個(gè)FastCache機(jī)制。該機(jī)制的實(shí)現(xiàn)過程主要包括以下幾個(gè)嚴(yán)謹(jǐn)且有序的步驟:

首先,系統(tǒng)會(huì)檢查是否存在SyncData數(shù)據(jù)。若存在,則立即將fastCacheOccupied標(biāo)志位設(shè)置為YES,以明確指示快速緩存中已存有有效數(shù)據(jù)。

緊接著,系統(tǒng)將執(zhí)行一項(xiàng)關(guān)鍵性檢查:驗(yàn)證當(dāng)前的SyncData對(duì)象是否與當(dāng)前操作所針對(duì)的目標(biāo)對(duì)象obj完全一致。若二者相符,則表明在快速緩存中已找到與目標(biāo)對(duì)象相匹配的鎖數(shù)據(jù)。

在確認(rèn)找到匹配鎖數(shù)據(jù)后,系統(tǒng)將讀取當(dāng)前鎖的lockCount值,并依據(jù)當(dāng)前傳入的操作類型(如加鎖或解鎖)來執(zhí)行相應(yīng)的操作。操作完成后,系統(tǒng)將更新后的lockCount值重新存儲(chǔ)回TLS中,以便在后續(xù)的查找操作中能夠迅速定位。

此FastCache機(jī)制的核心優(yōu)勢(shì)在于,它通過在各線程的本地存儲(chǔ)中預(yù)先緩存鎖數(shù)據(jù),有效提升了加鎖與解鎖操作的執(zhí)行效率。此舉不僅避免了頻繁的全局范圍查找與更新操作,還顯著降低了鎖資源的爭用情況,從而實(shí)現(xiàn)了對(duì)并發(fā)性能的顯著提升。

圖12 id2Data基本結(jié)構(gòu)之FastCache圖12 id2Data基本結(jié)構(gòu)之FastCache

4.6.2 SyncCache緩存遍歷查找

在FastCache快速查找機(jī)制未能成功定位目標(biāo)時(shí),程序?qū)⒂|發(fā)fetch_cache函數(shù)的執(zhí)行,以訪問當(dāng)前線程的緩存數(shù)據(jù),并繼續(xù)執(zhí)行查找操作。值得注意的是,SyncCache本質(zhì)上被設(shè)計(jì)為存儲(chǔ)SyncData元素的數(shù)組結(jié)構(gòu),這一過程實(shí)質(zhì)上是遍歷數(shù)組以查找與當(dāng)前操作對(duì)象obj相匹配的項(xiàng)。一旦找到匹配項(xiàng),程序?qū)⒏鶕?jù)傳入的操作類型執(zhí)行相應(yīng)的加鎖或解鎖操作,并同步更新lockCount的值。若lockCount遞減至0,則視為該線程已完成對(duì)該鎖的使用,隨即從線程緩存中移除該鎖實(shí)例。

為確保上述操作在多線程并發(fā)環(huán)境下的正確性和一致性,避免潛在的沖突問題,本機(jī)制采用OSAtomicDecrement32Barrier函數(shù)來原子性地減少result結(jié)構(gòu)體中threadCount的值。此舉旨在確保在減少計(jì)數(shù)器的過程中,不會(huì)被其他線程的加鎖操作所干擾,從而維護(hù)了系統(tǒng)狀態(tài)的穩(wěn)定與準(zhǔn)確。

圖13 id2Data基本結(jié)構(gòu)之SyncCache圖13 id2Data基本結(jié)構(gòu)之SyncCache

4.6.3 sDataLists查找

若快速緩存與常規(guī)緩存均未檢索到目標(biāo)項(xiàng),則此線程首次執(zhí)行@synchronized操作。在此情境下,系統(tǒng)轉(zhuǎn)而于sDataLists中檢索相應(yīng)的SyncData對(duì)象。首先,通過執(zhí)行l(wèi)ock操作對(duì)全局鏈表施以加鎖,此舉旨在防止多個(gè)線程并行創(chuàng)建同一對(duì)象的新鎖,確保線程安全。隨后,遍歷全局鏈表,以查找與當(dāng)前對(duì)象相匹配的SyncData實(shí)例。

若遍歷過程中成功定位到匹配的SyncData,則將該實(shí)例賦值予result變量,并利用OSAtomicDecrement32Barrier原子操作遞增result->threadCount的值,此舉旨在防范與并發(fā)的釋放操作發(fā)生潛在沖突,確保數(shù)據(jù)一致性與線程安全。完成上述步驟后,該SyncData的相關(guān)信息即可在TLS(線程局部存儲(chǔ))中被后續(xù)訪問。若系統(tǒng)檢測(cè)到存在未使用的SyncData實(shí)例,則優(yōu)先考慮復(fù)用此類資源,以優(yōu)化資源利用效率,減少不必要的對(duì)象創(chuàng)建與銷毀開銷。

圖14 id2Data基本結(jié)構(gòu)之sDataLists圖14 id2Data基本結(jié)構(gòu)之sDataLists

4.6.4 新建SyncData

若sDataLists中未能尋獲所需數(shù)據(jù),則需自行構(gòu)建SyncData并將其緩存至線程緩存,以備后續(xù)查詢之需。審視id2data的鎖獲取流程,其采用了一種類似于三級(jí)緩存的機(jī)制,即依次從快速緩存、常規(guī)緩存至哈希表進(jìn)行檢索。此設(shè)計(jì)旨在高效管理多線程環(huán)境中的鎖資源,確保線程能迅速獲得鎖以執(zhí)行加鎖與解鎖操作,從而提升系統(tǒng)效率。面對(duì)sDataLists檢索無果之情境,應(yīng)采取相應(yīng)策略,即創(chuàng)建SyncData的新實(shí)例,并將其妥善地納入緩存體系之中,以保障數(shù)據(jù)的完整性與系統(tǒng)的穩(wěn)定運(yùn)行。

圖15 id2Data基本結(jié)構(gòu)之SyncData創(chuàng)建圖15 id2Data基本結(jié)構(gòu)之SyncData創(chuàng)建

圖16 id2Data基本結(jié)構(gòu)之SyncData添加緩存圖16 id2Data基本結(jié)構(gòu)之SyncData添加緩存

總結(jié)

圖17 id2Data三級(jí)緩存機(jī)制圖17 id2Data三級(jí)緩存機(jī)制

通過本文上述自上而下的分析可以看出,@synchronized通過id2Data的三級(jí)緩存機(jī)制及時(shí)快速為傳入的對(duì)象obj拿到鎖,并清楚的記錄著這些鎖的lockCount及使用情況,確保在同一時(shí)間只有一個(gè)線程能夠執(zhí)行,從而達(dá)到防止數(shù)據(jù)競爭和保證線程安全的目的??梢钥偨Y(jié)出以下幾點(diǎn):

  1. @synchronized根據(jù)傳入的對(duì)象,為每個(gè)線程構(gòu)建一把遞歸鎖,同時(shí)記錄每個(gè)線程加鎖的次數(shù)?;诖?,對(duì)每條線程用不同的遞歸鎖進(jìn)行加鎖和解鎖的操作,從而達(dá)到多線程遞歸調(diào)用的目的。
  2. @synchronized內(nèi)部是基于os_unfair_lock封裝的遞歸互斥鎖,@synchronized在內(nèi)部創(chuàng)建鎖的時(shí)候?yàn)榱吮WC唯一性,使用spinlock_t來保證線程安全。
  3. @synchronized使用了快速緩存,線程緩存,全局鏈表方式來使得線程可以更加快速的拿到鎖,提升效率。
  4. 另外需要額外注意的是@synchronized使用時(shí)如果傳入nil,不能完成加鎖,使用時(shí)應(yīng)避免。

總之,在iOS開發(fā)過程中,@synchronized提供了一種便捷的線程同步機(jī)制,使得開發(fā)者能夠輕松實(shí)現(xiàn)線程同步。尤其是在處理遞歸鎖的情況下,使用@synchronized能夠有效地避免死鎖的發(fā)生,大大提高了代碼的安全性和可靠性。這一特性對(duì)于開發(fā)者來說非常重要,因?yàn)樗粌H確保了線程之間有序訪問共享資源,還降低了復(fù)雜度,使得開發(fā)者能夠更加專注于業(yè)務(wù)邏輯的實(shí)現(xiàn)。最后,本文探索iOS實(shí)現(xiàn)線程同步機(jī)制的過程,旨在同步系統(tǒng)開發(fā)領(lǐng)域?yàn)殚_發(fā)者提供具有參考價(jià)值的引導(dǎo)。

作者介紹

張璇,中國農(nóng)業(yè)銀行股份有限公司研發(fā)中心軟件研發(fā)工程師,熟悉iOS開發(fā),具備SpringBoot及React相關(guān)開發(fā)經(jīng)驗(yàn),具備扎實(shí)的計(jì)算機(jī)基礎(chǔ)知識(shí)儲(chǔ)備。

張凱,中國農(nóng)業(yè)銀行股份有限公司研發(fā)中心軟件研發(fā)工程師,擅長SpringBoot+Vue全棧式開發(fā),熱愛編程和學(xué)習(xí)前沿技術(shù)信息。


責(zé)任編輯:華軒 來源: 51CTO
相關(guān)推薦

2021-01-08 08:34:09

Synchronize線程開發(fā)技術(shù)

2024-03-07 07:47:04

代碼塊Monitor

2024-03-15 15:12:27

關(guān)鍵字底層代碼

2022-12-26 09:27:48

Java底層monitor

2009-12-08 10:07:29

2024-12-17 08:28:30

2013-03-27 10:32:53

iOS多線程原理runloop介紹GCD

2011-04-14 13:27:53

Synchronize多線程

2019-05-27 08:11:13

高并發(fā)Synchronize底層

2022-10-28 10:23:27

Java多線程底層

2011-06-22 13:57:54

Java多線程

2011-06-22 13:47:16

Java多線程

2018-10-25 15:55:44

Java多線程鎖優(yōu)化

2017-05-27 20:59:30

Java多線程synchronize

2009-06-29 18:44:28

Java多線程Synchronize同步變量

2009-06-29 18:32:52

Java多線程Synchronize

2025-03-27 04:00:00

2013-07-16 10:12:14

iOS多線程多線程概念多線程入門

2010-03-18 09:22:31

Java多線程遞歸

2015-07-22 09:39:38

IOS多線程同步
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)