一、结论

  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. 什么是报表工具?和 EXCEL 有什么区别?

    报表是什么? 带数据的表格和图表就都是报表,像工资表,考勤表,成绩表,资产负载表等等都是报表. 那报表工具,顾名思义就是用来做报表的工具,那 Excel 是不是也算报表工具?广义上讲当然也算.但 IT ...

  2. 重新整理 .net core 实践篇——— 测试控制器[四十九]

    前言 其实就是官方的例子,只是在此收录整理一下. 正文 测试控制器测试的是什么呢? 测试的是避开筛选器.路由.模型绑定,就是只测试控制器的逻辑,但是不测试器依赖项. 代码部分: https://git ...

  3. nginx重新整理——————nginx 的网络模型[九]

    前言 简单介绍一下nginx的网络模型. 正文 网络拓扑图: 数据流: 网络传输大概是这样传输的. nginx 事件循环: 事件处理过程: 上面两张图什么意思呢? 其实就是说,nginx 是通过事件驱 ...

  4. Docker compose 部署 nginx+php

    Docker compose 部署 nginx+php 拉取Docker镜像 docker pull nginx:1.21.6 docker pull php:7.4.28-fpm 创建docker- ...

  5. iOS自动化打包命令xcodebuild大全

    iOS实现自动化打包已经稳定运营几年了,不同的场景用到xcodebuild命令不一样,有的参数可能一直都用不到,列举一些常用的命令,比如编译命令: xcodebuild archive -worksp ...

  6. WPF/C#:让绘制的图形可以被选中并将信息显示在ListBox中

    实现的效果 如果你对此感兴趣,可以接着往下阅读. 实现过程 绘制矩形 比如说我想绘制一个3行4列的表格: private void Button_Click_DrawRect(object sende ...

  7. vue 弹出框挂载富文本,富文本()无法实例化问题

    因为elementUI的dialog组件,他是v-if渲染,再页面刚加载时,这个弹出框还未进行挂载,我们就让他v-show显示. ,富文本实例再mounted里面挂载即可

  8. HarmonyOS NEXT应用开发实战—组件堆叠

    介绍 本示例介绍运用Stack组件以构建多层次堆叠的视觉效果.通过绑定Scroll组件的onScroll滚动事件回调函数,精准捕获滚动动作的发生.当滚动时,实时地调节组件的透明度.高度等属性,从而成功 ...

  9. Serverless 架构模式及演进

    ​简介: Serverless 架构从使用技术上有计算,数据存储,消息通信,我们可从运维性,安全性,可靠性,可扩展性,成本几个角度来衡量架构的优劣.本文会介绍一些常见的业务场景,探讨如何使用 Serv ...

  10. python语言中的装饰器详解

        装饰器是一个用于封装函数或类的代码的工具.它显式地将封装器应用到函数或类上,从而使它们选择加入到装饰器的功能中.对于在函数运行前处理常见前置条件(例如确认授权),或在函数运行后确保清理(例如输 ...