@synchronized
介绍:@syncheinized也是互斥锁,相比其他锁使用比较简单,只需将临界资源放在@synchronized里面即可,如下
@synchronized (self) {
[arr addObject:item];//防止不同线程向同时操作数组
}
官方文档中描述@synchronized的block添加了异常处理,有异常时将自动释放互斥量。
实现细节:Xcode编译后@s ynchronized的block会变成objc_sync_enter和objc_sync_exit,objc_sync_enter和objc_sync_exit代替blcok将临界区保护起来,这个成对调用的底层使用递归锁来实现,下面我们分析在runtime源码看一下系统何时怎样分配的递归锁呢?
int objc_sync_enter(id obj)
{
int result = OBJC_SYNC_SUCCESS;、
if (obj) {
SyncData* data = id2data(obj, ACQUIRE);
assert(data);
data->mutex.lock();
} else {
// @synchronized(nil) does nothing
if (DebugNilSync) {
_objc_inform("NIL SYNC DEBUG: @synchronized(nil); set a breakpoint on objc_sync_nil to debug");
}
objc_sync_nil();
}
return result;
}
// End synchronizing on 'obj',Returns OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR
int objc_sync_exit(id obj)
{
int result = OBJC_SYNC_SUCCESS;
if (obj) {
SyncData* data = id2data(obj, RELEASE);
if (!data) {
result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
} else {
bool okay = data->mutex.tryUnlock();
if (!okay) {
result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
}
}
} else {
// @synchronized(nil) does nothing
}
return result;
}
首先,我们看一下objc_sync_enter方法,这个方法里面创建了一个SyncData对象,并且给SyncData对象分配了一个mutex锁,也就是在进入block时,创建SyncData对象,并且分配递归锁。而SyncData对象的结构如下,它是一个结构体,结构里面的object接收objc_sync_enter传进来的obj,结构里面的mutex是与对象关联的锁,nextData指向另一个SyncData对象的指针,threadCount表示想获取锁的线程,结构体里面的mutex可能被其他线程请求,所以记录一下使请求该锁的线程数;SyncData可看作SyncList链表中的节点, SyncList结构体中data是指向 SyncData节点链表头部的指针,lock是防止多个线程操作SyncLIst列表使用的锁。
typedef struct SyncData {
id object;
recursive_mutex_t mutex;
struct SyncData* nextData;
int threadCount;
} SyncData;
typedef struct SyncList {
SyncData *data;
spinlock_t lock;
} SyncList;
//通过定义的一个哈希算法将传入对象映射到数组上的一个下标。LOCK_FOR_OBJ(obj)和LIST_FOR_OBJ(obj)先是哈希出对象的数组下标,然后取出数组对应元素的lock或data
// Use multiple parallel lists to decrease contention among unrelated objects.
#define LOCK_FOR_OBJ(obj) sDataLists[obj].lock
#define LIST_FOR_OBJ(obj) sDataLists[obj].data
static StripedMap<SyncList> sDataLists;
当你调用 objc_sync_enter(obj)时,它用 obj内存地址的哈希值查找合适的SyncData,然后将其上锁。当你调用objc_sync_exit(obj)时,它查找合适的 SyncData并将其解锁。
参考:关于 @synchronized,这儿比你想知道的还要多
https://juejin.im/post/6844904086161063944