@synchronized是线程同步锁,易用、可读性高。

@synchronized(self) {
  临界区
}

利用如下命令将其重写

clang -rewrite-objc file 

得到C++实现

{
id _sync_obj = (id)self;
objc_sync_enter(_sync_obj);
struct _SYNC_EXIT {
_SYNC_EXIT(id arg) : sync_exit(arg) {}
~_SYNC_EXIT() {
objc_sync_exit(sync_exit);
}
id sync_exit;
} _sync_exit(_sync_obj);
}

深究objc_sync_enter和objc_sync_exit的源码

int objc_sync_enter(id obj)
{
if (obj) {
SyncData* data = id2data(obj, ACQUIRE);
recursive_mutex_lock(&data->mutex); // 获取递归锁
} else {
// @synchronized(nil) does nothing
}
}
int objc_sync_exit(id obj)
{
if (obj) {
SyncData* data = id2data(obj, RELEASE);
recursive_mutex_unlock(&data->mutex); // 释放递归锁
} else {
// @synchronized(nil) does nothing
}
}

可以看到

1、@synchronized底层用的是递归锁,即同个线程可重入,而不会导致死锁。

2、@synchronized(nil)是不会上锁的。

接着,显然SyncList是单链表,SyncData是其中的节点,而整体的存储则是一个“拉链哈希表”。

typedef struct SyncData {
struct SyncData* nextData; // 指向下一个SyncData节点
DisguisedPtr<objc_object> object; // @synchronized的参数,即上面的self
recursive_mutex_t mutex; // 递归锁
} SyncData; struct SyncList {
SyncData *data; // 单链表的头指针
spinlock_t lock; // 自旋锁,性能好,但不绝对安全
SyncList() : data(nil) { }
};
#define LOCK_FOR_OBJ(obj) sDataLists[obj].lock // 根据参数获取单链表的锁
#define LIST_FOR_OBJ(obj) sDataLists[obj].data // 根据参数获取单链表
static StripedMap<SyncList> sDataLists; // 哈希表
// 根据参数获取对应的SyncData节点,其实就是哈希表查找
static SyncData* id2data(id object, enum usage why)
{
spinlock_t *lockp = &LOCK_FOR_OBJ(object);
SyncData **listp = &LIST_FOR_OBJ(object); // 参数对应的单链表
SyncData* result = NULL; lockp->lock();
{
SyncData* p;
// 遍历单链表
for (p = *listp; p != NULL; p = p->nextData) {
if ( p->object == object ) {
// 找到参数对应的SyncData节点
result = p;
goto done;
}
}
}
// 单链表中还没有参数对应的SyncData节点
result = (SyncData*)calloc(sizeof(SyncData), 1);
result->object = (objc_object *)object; // 填充数据
new (&result->mutex) recursive_mutex_t();
   // 新建的SyncData节点往链表头部加
result->nextData = *listp;
*listp = result;
done:
lockp->unlock();
return result;
}
template<typename T>
class StripedMap {
static unsigned int indexForPointer(const void *p) {
// 取参数地址的哈希值作为数组的index
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
return ((addr >> 4) ^ (addr >> 9)) % StripeCount;
}
public:
T& operator[] (const void *p) {
return array[indexForPointer(p)].value;
}
};   

可以看出,参数和递归锁是一一对应的。因此,一定要保证参数不变,这里的不变,指的是完全不变,包括地址。

源码:

https://opensource.apple.com/source/objc4/objc4-680/runtime/objc-sync.mm

@synchronized深入理解的更多相关文章

  1. 对于synchronized的理解

    一.synchronized 同步关键字,分为同步代码块和同步函数 二.对synchronized的理解(未加static关键字)(以下所说:对同步方法和同步代码块均适用) 对象的创建是以类为模板的 ...

  2. Java中synchronized关键字理解

    好记性不如烂笔头~~ 并发编程中synchronized关键字的地位很重要,很多人都称它为重量级锁.利用synchronized实现同步的基础:Java中每一个对象都可以作为锁.具体表现为以下三种形式 ...

  3. synchronized的理解

    用法解释 synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调 ...

  4. Java线程同步synchronized的理解

    JVM中(留神:马上讲到的这两个存储区只在JVM内部与物理存储区无关)存在一个主内存(Main Memory),Java中所有的变量存储在主内存中,所有实例和实例的字段都在此区域,对于所有的线程是共享 ...

  5. synchronized(this) 与 synchronized(class) 理解

    1.概念 synchronized 是 Java 中的关键字,是利用锁的机制来实现同步的. 锁机制有如下两种特性: 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机 ...

  6. java并发编程--Synchronized的理解

    synchronized实现锁的基础:Java中每一个对象都可以作为锁,具体表现为3种形式. (1)普通同步方法,锁是当前实例对象 (2)静态同步方法,锁是当前类的Class对象 (3)同步方法块,锁 ...

  7. 【多线程与高并发原理篇:4_深入理解synchronized】

    1. 前言 越是简单的东西,在深入了解后发现越复杂.想起了曾在初中阶段,语文老师给我们解说<论语>的道理,顺便给我们提了一句,说老子的无为思想比较消极,学生时代不要太关注.现在有了一定的生 ...

  8. volatile synchronized AtomicInteger的区别

    在网络上看了很多关于他们两个的区别与联系,今天用自己的话表述一下: synchronized 容易理解,给一个方法或者代码的一个区块加锁,那么需要注意的是,加锁的标志位默认是this对象,当然聪明的你 ...

  9. Synchronized用法原理和锁优化升级过程(面试)

    简介 多线程一直是面试中的重点和难点,无论你现在处于啥级别段位,对synchronized关键字的学习避免不了,这是我的心得体会.下面咱们以面试的思维来对synchronized做一个系统的描述,如果 ...

随机推荐

  1. 如何用minitab检测一组数据是否服从正态分布

    打开Minitab之后 点击Stat>Basic Statistics> Normality Test  分析之后若 P value(P值)>0.05,说明此组数据服从正态分布

  2. JavaSE 软件工程师 认证考试试卷3

    JavaSE 软件工程师 认证考试试卷   笔试   考试时间150分钟 总分 100分   姓    名_______________________ 身份证号___________________ ...

  3. sql: Query to Display Foreign Key Relationships and Name of the Constraint for Each Table in Database

    --20170505 --塗聚文 Geovin Du CREATE DATABASE DuMailSystem GO USE DuMailSystem GO --1查詢表的及备注说明 SELECT S ...

  4. 用JS来实现的第一个简单游戏 :贪吃蛇

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. Node.js+Koa开发微信公众号个人笔记(一)准备工作

    本人也是在学习过程中,所以文章只作为学习笔记,如果能帮到你,那就更好啦~当然也难免会有错误,请不吝指出~ 一.准备工作 1.本人学习教程:慕课网Scott老师的<Node.js七天搞定微信公众号 ...

  6. 微信小程序顶部(navigationBar)设置为透明

    我记得在微信小程序中导航栏的颜色可以在app.json.  window里面添加navigationBarBackgroundColor属性,但是颜色只能为纯色.不能使用rgb,或者rgba的色号. ...

  7. 2018最新大厂Android面试真题

    前言 又到了金三银四的面试季,自己也不得不参与到这场战役中来,其实是从去年底就开始看,android的好机会确实不太多,但也还好,3年+的android开发经历还是有一些面试机会的,不过确实不像几年前 ...

  8. 最全的android学习资料

    一.开发环境搭建 (已完成) 负责人:kris 状态:已完成 所整理标签为:搭建 SDK JDK NDK Eclipse ADT 模拟器 AVD 调试器(DEBUG) DDMS 测试 日志 Logca ...

  9. (网页)javascript该如何学习?怎么样才能学好?

    文章摘抄自强哥文章   很多刚刚涉足软件开发的差不多都是只懂得HTMLCSS不懂得javascript,所以就想学习js,于是就从网上搜各种视频,或者买各种书籍回来看,很多时候都是浪费时间,因为根本看 ...

  10. 工作中常用到的Vim命令

    最近工作中需要到linux服务器上更改文件,苦于对vim的各种命令不熟悉,今天特此总结并熟悉一下各种vim命令,好提高工作效率.后期持续更新 vim编辑器个人设置 先复制一份vim配置模板到个人目录下 ...