关于 Synchronized 的一个点,网上99%的文章都错了(中)

简介: 关于 Synchronized 的一个点,网上99%的文章都错了(中)

我们再来继续深入 synchronized

从上文我们已经知道 synchronized 是作用于对象身上的,但是没细说,我们接下来剖析一波。

在 Java 中,对象结构分为对象头、实例数据和对齐填充。

而对象头又分为:MarkWord 、 klass pointer、数组长度(只有数组才有),我们的重点是锁,所以关注点只放在 MarkWord 上。


image.png


我再画一下 64 位时 MarkWord 在不同状态下的内存布局(里面的 monitor 打错了,但是我不准备改,留个印记哈哈)。


image.png


MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处。

记住这个图啊,各种锁操作都和这个 MarkWord 有很强的联系。

从图中可以看到,在重量级锁时,对象头的锁标记位为 10,并且会有一个指针指向这个 monitor 对象,所以锁对象和 monitor 两者就是这样关联的。


image.png


而这个 monitor 在 HotSpot 中是 c++ 实现的,叫 ObjectMonitor,它是管程的实现,也有叫监视器的。

它长这样,重点字段我都注释了含义,还专门截了个头文件的注释:


image.png


暂时记忆一下,等下源码和这几个字段关联很大。

synchronized 底层原理

先来一张图,结合上面 monitor 的注释,先看看,看不懂没关系,有个大致流转的印象即可:


image.png

好,我们继续。

前面我们提到了 monitorenter 这个指令,这个指令会执行下面的代码:


image.png


我们现在分析的是重量级锁,所以不关心偏向的代码,而 slow_enter 方法文章一开始的截图就是了,最终会执行到 ObjectMonitor::enter 这个方法中。


image.png


可以看到重点就是通过 CAS 把 ObjectMonitor 中的 _owner 设置为当前线程,设置成功就表示获取锁成功

然后通过 recursions 的自增来表示重入。

如果 CAS 失败的话,会执行下面的一个循环:


image.png


EnterI 的代码其实上面也已经截图了,这里再来一次,我把重要的入队操作加上,并且删除了一些不重要的代码:


image.png


先再尝试一下获取锁,不行的话就自适应自旋,还不行就包装成 ObjectWaiter 对象加入到 _cxq 这个单向链表之中,挣扎一下还是没抢到锁的话,那么就要阻塞了,所以下面还有个阻塞的方法。


image.png


可以看到不论哪个分支都会执行 Self->_ParkEvent->park(),这个就是上文提到的调用 pthread_mutex_lock

至此争抢锁的流程已经很清晰了,我再画个图来理一理。


image.png


接下来再看看解锁的方法

ObjectMonitor::exit 就是解锁时会调用的方法。


image.png


可重入锁就是根据 _recursions 来判断的,重入一次 _recursions++,解锁一次 _recursions--,如果减到 0 说明需要释放锁了。

然后此时解锁的线程还会唤醒之前等待的线程,这里有好几种模式,我们来看看。

如果 QMode == 2 && _cxq != NULL的时候:


image.png

image.png

至此,解锁的流程就完毕了!我再画一波流程图:

image.png



相关文章
|
3月前
|
搜索推荐 大数据 数据处理
面试官:try-catch 到底写在循环里面好,还是外面好?大部分人都会答错!
面试官:try-catch 到底写在循环里面好,还是外面好?大部分人都会答错!
48 0
C真的不难学,不信就看下我关于循环的理解
C真的不难学,不信就看下我关于循环的理解
|
算法 安全 Java
Java多线程与并发框(完结篇)——再看不懂我找不到女朋友
Java多线程与并发框(完结篇)——再看不懂我找不到女朋友
65 0
Java多线程与并发框(完结篇)——再看不懂我找不到女朋友
|
算法 C++
没什么。。。。
没什么。。。。
|
机器学习/深度学习 算法 C++
没什么了。
没什么了。
|
移动开发 缓存 ARouter
没错,TheRouter 是我写的
大约在17年底到18年初的时候,我经常会讲一些当时做模块化开发的心得和踩坑历程
223 0
|
存储 负载均衡 算法
HASH碰撞问题一直没真正搞懂?这下不用慌了
散列函数(英语:Hash function)又称散列算法、哈希函数,是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新创建一个叫做散列值(hash values,hash codes,hash sums,或hashes)的指纹。散列值通常用一个短的随机字母和数字组成的字符串来代表。
HASH碰撞问题一直没真正搞懂?这下不用慌了
|
Java 编译器 Linux
关于 Synchronized 的一个点,网上99%的文章都错了(上)
关于 Synchronized 的一个点,网上99%的文章都错了(上)
关于 Synchronized 的一个点,网上99%的文章都错了(上)
|
存储 安全 Java
关于 Synchronized 的一个点,网上99%的文章都错了(下)
关于 Synchronized 的一个点,网上99%的文章都错了(下)
关于 Synchronized 的一个点,网上99%的文章都错了(下)
|
安全
当Synchronized遇到这玩意儿,有个大坑,要注意! (上)
当Synchronized遇到这玩意儿,有个大坑,要注意! (上)
200 0
当Synchronized遇到这玩意儿,有个大坑,要注意! (上)