一、结论

  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 可以看成一个函数,加锁的对象是后面传入对象的地址,所以如果加锁对象重新赋值,那么地址会重新该表导致加锁失效。

     如果这个对象为nil,那么等于没有加锁。

    内部实现源代码如下:

    

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/d83b3b7d5a5a

    

关于@synchronized的更多相关文章

  1. java 多线程 Synchronized方法和方法块 synchronized(this)和synchronized(object)的理解

    synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synchronized ...

  2. 单例模式中用volatile和synchronized来满足双重检查锁机制

    背景:我们在实现单例模式的时候往往会忽略掉多线程的情况,就是写的代码在单线程的情况下是没问题的,但是一碰到多个线程的时候,由于代码没写好,就会引发很多问题,而且这些问题都是很隐蔽和很难排查的. 例子1 ...

  3. Thread 学习记录 <1> -- volatile和synchronized

    恐怕比较一下volatile和synchronized的不同是最容易解释清楚的.volatile是变量修饰符,而synchronized则作用于一段代码或方法:看如下三句get代码: int i1;  ...

  4. synchronized使用说明

    好久没有更新博客了,今天试着用简单的语言把synchronized的使用说清楚. synchronized是什么? synchronized是用来保证在多线程环境下代码同步执行的可重入的互斥锁.所谓互 ...

  5. 【Java并发系列04】线程锁synchronized和Lock和volatile和Condition

    img { border: solid 1px } 一.前言 多线程怎么防止竞争资源,即防止对同一资源进行并发操作,那就是使用加锁机制.这是Java并发编程中必须要理解的一个知识点.其实使用起来还是比 ...

  6. (转)Lock和synchronized比较详解

    今天看了并发实践这本书的ReentantLock这章,感觉对ReentantLock还是不够熟悉,有许多疑问,所有在网上找了很多文章看了一下,总体说的不够详细,重点和焦点问题没有谈到,但这篇文章相当不 ...

  7. Synchronized同步性与可见性

    Synchronized是具有同步性与可见性的,那么什么是同步性与可见性呢? (1)同步性:同步性就是一个事物要么一起成功,要么一起失败,可谓是有福同享有难同当,就像A有10000去银行转5000给身 ...

  8. 基于synchronized 或 ReadWriteLock实现 简单缓存机制

    package cn.xxx.xxx; import java.util.HashMap; import java.util.Map; import java.util.concurrent.lock ...

  9. 【Java并发编程实战】-----synchronized

    在我们的实际应用当中可能经常会遇到这样一个场景:多个线程读或者.写相同的数据,访问相同的文件等等.对于这种情况如果我们不加以控制,是非常容易导致错误的.在java中,为了解决这个问题,引入临界区概念. ...

  10. Lock、ReentrantLock、synchronized、ReentrantReadWriteLock使用

    先来看一段代码,实现如下打印效果: 1 2 A 3 4 B 5 6 C 7 8 D 9 10 E 11 12 F 13 14 G 15 16 H 17 18 I 19 20 J 21 22 K 23 ...

随机推荐

  1. 深度解读《深度探索C++对象模型》之拷贝构造函数

    接下来我将持续更新"深度解读<深度探索C++对象模型>"系列,敬请期待,欢迎关注!也可以关注公众号:iShare爱分享,自动获得推文. 写作不易,请有心人到我的公众号上 ...

  2. https http2 http3

    HTTP 1.1 对比 1.0,HTTP 1.1 主要区别主要体现在: 缓存处理:在 HTTP 1.0 中主要使用 header 里的 If-Modified-Since,Expires 来做为缓存判 ...

  3. js深浅复制(拷贝)

    从两种数据类型说起 在js中,变量的类型可以大致分成两种:基本数据类型和引用数据类型,其中基本数据类型指的是简单的数据段,包括: Undefined Null Boolean Number Strin ...

  4. 力扣196(MySQL)-删除重复的电子邮箱(简单)

    题目: 表: Person 编写一个 SQL 删除语句来 删除 所有重复的电子邮件,只保留一个id最小的唯一电子邮件. 以 任意顺序 返回结果表. (注意: 仅需要写删除语句,将自动对剩余结果进行查询 ...

  5. 数据湖揭秘—Delta Lake

    ​简介:Delta Lake 是 DataBricks 公司开源的.用于构建湖仓架构的存储框架.能够支持 Spark,Flink,Hive,PrestoDB,Trino 等查询/计算引擎.作为一个开放 ...

  6. Kubernetes 稳定性保障手册 -- 极简版

    简介: Kubernetes 在生产环境中的采用率越来越高,复杂度越来越高,由此带来的稳定性保障的挑战越来越大. Kubernetes 在生产环境中的采用率越来越高,复杂度越来越高,由此带来的稳定性保 ...

  7. dockerfile构建镜像常用命令

    一.什么是dockerfile Dockerfile是一个包含用于组合映像的命令的文本文档.可以使用在命令行中调用任何命令. Docker通过读取Dockerfile中的指令自动生成映像. docke ...

  8. 使用Vue3在浏览器端进行zip文件压缩

    在前端开发中,我们时常需要处理文件上传和下载的功能.有时,用户可能希望将多个文件打包成一个zip文件以便于下载.今天,我将分享一个使用Vue3和JSZip库在浏览器端实现zip文件压缩的示例. 首先, ...

  9. JUC并发编程学习笔记(十八)深入理解CAS

    深入理解CAS 什么是CAS 为什么要学CAS:大厂你必须深入研究底层!有所突破! java层面的cas------->compareAndSet compareAndSet(int expec ...

  10. 使用beego/bee热启动gin框架

    目录 1.需要关闭gomod 2.安装 bee 3.再开启gomod 4.启动服务 效果: 1.需要关闭gomod export GO111MODULE=off 2.安装 bee go get -u ...