1、結論swift
1)@synchronized內部使用的是recursive_mutex_lock,也就是遞歸鎖,對於統一線程來講,@synchronized加鎖的方法能夠重複加鎖。安全
好比代碼:多線程
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self testA]; } - (void)testA { @synchronized(self) { NSLog(@"AAAAAA"); [self testB]; } } - (void)testB { @synchronized(self) { NSLog(@"BBBBBB"); } }
輸出結果爲:函數
2018-08-21 15:25:51.058333+0800 TestSynchronized2[17367:7864821] AAAAAA 2018-08-21 15:25:51.058372+0800 TestSynchronized2[17367:7864821] BBBBBB
2)@synchronized 能夠當作一個函數,加鎖的對象是後面傳入對象的地址,因此若是加鎖對象從新賦值,那麼地址會從新該表致使加鎖失效。ui
若是這個對象爲nil,那麼等於沒有加鎖。this
內部實現源代碼以下:線程
static void _I_Demo_synchronizedTest(Demo * self, SEL _cmd) { NSMutableArray *arr; { id _sync_obj = (id)arr; objc_sync_enter(_sync_obj); // 同步鎖進入,參數是arr try { struct _SYNC_EXIT { _SYNC_EXIT(id arg) : sync_exit(arg) {} ~_SYNC_EXIT() {objc_sync_exit(sync_exit); // 同步鎖退出,參數是arr } id sync_exit; } _sync_exit(_sync_obj);// 調用結構體的構造函數,參數是arr } catch (id e) { } } } int objc_sync_enter(id obj) { int result = OBJC_SYNC_SUCCESS; if (obj) { // 根據obj獲取對應的SyncData節點,id2data函數在下面有解析 SyncData* data = id2data(obj, ACQUIRE);// 上鎖 result = recursive_mutex_lock(&data->mutex); } else { // @synchronized(nil) does nothing } return result; } typedef struct SyncData { struct SyncData* nextData; // 指向下一個SyncData節點的指針 DisguisedPtr<objc_object> object; // @synchronized的參數obj int32_t threadCount; // number of THREADS using this block recursive_mutex_t mutex; // 遞歸鎖 } SyncData; struct SyncList { SyncData *data; // 單鏈表頭指針 spinlock_t lock; // 保證多線程安全訪問該鏈表 SyncList() : data(nil) { } }; static StripedMap<SyncList> sDataLists; // 哈希表,key:obj,value:單鏈表 // 根據obj獲取對應的SyncData節點static SyncData* id2data(id object, enum usage why) { spinlock_t *lockp = &LOCK_FOR_OBJ(object); // SyncList鎖 SyncData **listp = &LIST_FOR_OBJ(object); // obj對應的SyncData節點所在的 SyncList SyncData* result = NULL;// 這裏省略一大坨cache代碼 lockp->lock(); { SyncData* p; SyncData* firstUnused = NULL; // 遍歷單鏈表 for (p = *listp; p != NULL; p = p->nextData) { if ( p->object == object ) { // 找到obj對應的SyncData節點 result = p; // SyncData節點對應的線程數加1 OSAtomicIncrement32Barrier(&result->threadCount); goto done; } // SyncData節點對應的遞歸鎖沒有線程在用了,回收重用,能夠節省節點建立的時間和空間 if ( (firstUnused == NULL) && (p->threadCount == 0) ) firstUnused = p; } // 鏈表中尚未obj對應的SyncData節點,可是有可重用的SyncData節點 // an unused one was found, use it if ( firstUnused != NULL ) { result = firstUnused; result->object = (objc_object *)object; result->threadCount = 1; goto done; } } // 鏈表中尚未obj對應的SyncData節點,並且沒有可重用的SyncData節點 result = (SyncData*)calloc(sizeof(SyncData), 1); result->object = (objc_object *)object; result->threadCount = 1; new (&result->mutex) recursive_mutex_t(); // 新建的SyncData節點往鏈表頭部加 result->nextData = *listp; *listp = result; done: lockp->unlock(); return result;}
3)swift中沒有對應的方法,可是依然能夠使用OC中調用加鎖的函數,實現以下指針
func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T { objc_sync_enter(lock) defer { objc_sync_exit(lock) } return try body() }
參考資料:對象
做者:悲觀患者
連接:https://www.jianshu.com/p/d83b3b7d5a5ablog