Java 加锁与解锁
今天看极客时间的时候看到了 java 锁的一篇文章,其中关于加锁与解锁的几个点不是特别理解,晚上专门差了一下资料,算是弄明白了。
疑问
为什么解锁的时候,cas 释放失败就证明有其他线程来获取过锁呢?
原理
每一个java对象都拥有一个对象头,对象头分为2个部分:Mark Word(标记字段) 与 Class Pointer(类型指针)。
- Mark Word用于存储对象自身的运行时数据,自身运行时的数据:哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等,它是实现轻量级锁和偏向锁的关键。
- Class Pointer是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
32位虚拟机的Mark Word如下:
分析
先说一下锁的种类:偏向锁,轻量级锁,重量级锁。
偏向锁
获取流程:
- 确认对象是可偏向状态(是否偏向:1,锁标致:01);
- 可偏向,查询 Mark Word 中
线程ID
是否为当前线程ID,是则进行5,不是则3; - 未指向当前线程,则 CAS 尝试获取锁,获取成功,将 Mark Word 中线程ID更换,执行5,否则执行4;
- 如果获取失败,则说明有线程竞争,那么在 safe-point 安全点时,获取锁的线程挂起,升级为轻量级锁,然后被阻塞在安全点的线程继续执行后面的代码;
- 执行代码。
释放流程:
不主动释放,只有当出现竞争,进入到安全点时才会触发释放逻辑
,这也是3为什么会获取成功的原因。
结果是要么释放被其他线程获取,要么升级轻量级锁。
轻量级锁
获取流程:
- 线程进入同步代码块时,如果是偏向锁的状态;线程在自己的栈帧空间内建立一个 Mark Record 的空间,用于存储 Mark Word 的备份,官方称为 Displaced Marl Word,这是线程与对象头的状态是这样的:
- 拷贝 Mark Word 到 Lock Record 中;
- CAS 尝试将对象头的 Mark Word 指向 Lock Record,并将 Lock Record 中的 owner 执行 mark word,如果成功执行4,否则5;
- 如果更新成功,就证明得到锁,并将锁标致位更新为00,表示对象处于轻量级锁,此时线程与对象头的状态:
- 如果更新失败,jvm 先判断 mark word 是否指向当前栈帧,如果是代表线程已经获取锁,进入重入状态;如果不是证明已经被其他线程获取,自旋等待一定时间,如果仍未获取,升级为重量级锁(
将 mark work 从指向线程指针改为指向互斥量
)。
释放流程
- 通过 CAS 将线程中复制的 Displaced Mark Work 替换会原先的 Mark Word;
- 替换失败,说明有其他线程尝试过获取该锁(此时锁已膨胀),那就要在释放锁的同时,唤醒被挂起的线程。
这里说一下轻量级锁释放失败是就证明锁升级的原理,因为之前 mark word 指向的是本线程的指针,这个是 cas 期望的值,但是被其他线程更改为了指向互斥量的对象了,cas 就失败,就证明升级为了重量级锁。
参考文档
https://www.itqiankun.com/art...
https://juejin.im/post/5b4eec...
7 声望
3 粉丝
推荐阅读
Liquibase 数据库版本管理工具:3. changeSet 变更集详解
上篇文章中详细了介绍了一下changelog 文件的使用,本篇文章将详细说一下 changeSet 变更集 中的细节,以及通常的使用方式 1.变更集分类 changeSet 分为 6类: add create drop rename sql other 官方文档:[链接...
哒哒队长赞 1阅读 4k评论 1
Java 编译器 javac 及 Lombok 实现原理解析
javac 是 Java 代码的编译器12,初学 Java 的时候就应该接触过。本文整理一些 javac 相关的高级用法。Lombok 库,大家平常一直在使用,但可能并不知道实现原理解析,其实 Lombok 实现上依赖的是 Java 编译器的注...
nullwy赞 10阅读 6k
与RabbitMQ有关的一些知识
工作中用过一段时间的Kafka,不过主要还是RabbitMQ用的多一些。今天主要来讲讲与RabbitMQ相关的一些知识。一些基本概念,以及实际使用场景及一些注意事项。
lpe234赞 8阅读 1.8k
Git操作不规范,战友提刀来相见!
年终奖都没了,还要扣我绩效,门都没有,哈哈。这波骚Git操作我也是第一次用,担心闪了腰,所以不仅做了备份,也做了笔记,分享给大家。问题描述小A和我在同时开发一个功能模块,他在优化之前的代码逻辑,我在开...
王中阳Go赞 5阅读 2k评论 2
Redis 发布订阅模式:原理拆解并实现一个消息队列
“65 哥,如果你交了个漂亮小姐姐做女朋友,你会通过什么方式将这个消息广而告之给你的微信好友?““那不得拍点女朋友的美照 + 亲密照弄一个九宫格图文消息在朋友圈发布大肆宣传,暴击单身狗。”像这种 65 哥通过朋...
码哥字节赞 6阅读 1.2k
NB的Github项目,看到最后一个我惊呆了!
最近看到不少好玩的、实用的 Github 项目,就来给大家推荐一把。中国制霸生成器最近在朋友圈非常火的一个小网站,可以在线标记 居住、短居、游玩、出差、路过 标记后可生成图片进行社区分享,标记过的信息会记录...
艾小仙赞 5阅读 1.5k评论 1
好好的系统,为什么要分库分表?
今天是《分库分表 ShardingSphere 原理与实战》系列的开篇文章,之前写过几篇关于分库分表的文章反响都还不错,到现在公众号:程序员小富后台不断的有人留言、咨询分库分表的问题,我也没想到大家对于分库分表的话...
程序员小富赞 3阅读 1.5k
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。