我測試的iOS同步鎖包括@synchronsized、NSLock、NSCondition、NSConditionLock、NSRecursiveLock、pthread_mutex_t、OSSpinLock。
先貼出測試用的代碼:

在模擬器下運行的性能對比(Xcode7.3,iOS 9.3):

在iPhone 6s上運行的性能對比(iOS 9.3):

從以上的輸出可以看出:
首先,模擬器和真機測試的結(jié)果是有差異的,而且差異還比較大。因而,還是從真機的測試結(jié)果來分析同步鎖。
從輸出結(jié)果可以看出,@synchronize的開銷是其它同步鎖開銷的三倍左右,而NSConditionLock與NSRecursiveLock的開銷差不多(后者更優(yōu)一些),剩下三者的性能處于同一級別:OSSpinLock > pthread_mutex_t > NSLock。
@synchronize 的開銷很大是因為它必須要設(shè)置一個異常處理的塊(Exception Handler),這確實是要耗費內(nèi)部鎖的性能。
OSSpinLock則根本不需要進(jìn)入到內(nèi)核中,它只是一直不停地去重載(試圖訪問)這個鎖,直到這個鎖處于unlock狀態(tài)。如果鎖所保持的時間很長,那情況會變得很糟糕,甚至?xí)霈F(xiàn)死鎖,但是,它節(jié)省了昂貴的系統(tǒng)開銷和一對上下文開關(guān)。在最新的iOS版本中已經(jīng)不推薦使用OSSpinLock,因為它已經(jīng)不是線程安全的了。具體可以參見http://blog.ibireme.com/2016/01/16/spinlock_is_unsafe_in_ios/?utm_source=tuicool&utm_medium=referral??
pthread_mutex_t事實上是當(dāng)沒有競爭的時候,它會使用OSSpinLock來使程序運行流暢,當(dāng)競爭出現(xiàn)時,它會轉(zhuǎn)而采用更繁重的內(nèi)核級的同步鎖/任務(wù)方式。
因此,倘若你的鎖是容易出現(xiàn)競爭的鎖,那么OSSpinLock就不適合,除非你加鎖的區(qū)域運行的速度非常非常快。pthread_mutex_t的開銷比OSSpinLock稍多一些,但是它避免了OSSpinLock所帶來的性能上的浪費。
NSLock是對pthread_mutex_t的很好的封裝,除了封裝之外,也并不提供別的東西,因此,它的開銷不會比pthread_mutex_t多很多。
NSLock與@synchronized都是用的互斥鎖,它們就像在共同的實體上實現(xiàn)的兩個不同的接口。NSLock創(chuàng)建的是顯式鎖,而@synchronized創(chuàng)建的是隱式鎖。顯式鎖的好處就是編譯器能夠很好的理解它,并且處理邊界問題,但是它們的行為是相同的。
NSRecursiveLock實際上是一個遞歸鎖,它可以允許統(tǒng)一鮮橙多次加鎖,而不會造成死鎖。它會跟蹤它被lock的次數(shù),每次成功的lock必須平衡調(diào)用unlock操作,只有這樣鎖最后才能被釋放。
@synchronized是如何運行的?
在寫有@synchronized的代碼塊中我發(fā)現(xiàn)了一些東西:

這是對一個在共享的資源中的簡單鎖的分解。在這種情況下,我們不需要考慮異常安全的問題,因為它會設(shè)置一個exception handler。通過翻看蘋果的文檔objc_sync.m中關(guān)于objc_sync_enter和objc_sync_exit的實現(xiàn),我們可以知道每一個@synchronized(id obj)鎖都包含三組lock/unlock序列。objc_sync_enter調(diào)用id2data(對取得與obj相關(guān)聯(lián)的鎖負(fù)責(zé))來上鎖。objc_sync_exit也調(diào)用id2data來取得與obj相關(guān)聯(lián)的鎖并解鎖。同時,id2data必須對它自己內(nèi)部的數(shù)據(jù)結(jié)構(gòu)執(zhí)行加鎖/解鎖操作來使得它能夠安全的獲得與obj相關(guān)聯(lián)的鎖,因此,我們要對每一對鎖付出開銷。