本文是我在阅读 《深入理解Java虚拟机-第三版》和 极客时间 郑宇迪对于JVM的剖析后做的总结,如有不妥,不明白的地方,欢迎斧正
下面是一张比较经典的 Java 虚拟机锁实现流程图,不了解JVM的具体锁实现可能会不太明白

字节码上的实现

声明 synchronized 代码块时,编译而成的字节码将包含 monitorentermonitorexit 指令,一般会包含一个monitorenter和多个monitorexit,确保在函数所有的出口都能释放锁

sycnchronized 声明函数时,会在访问标志中声明 ACC_SYNCHRONIZED ,是告诉 JVM 需要对该函数进行加锁解锁,声明函数时,在 Code 中,monitorenter和monitorexit都是隐式的

通过monitorenter和monitorexit对锁对象的锁技术器进行加减,为0时,意味着没有被任何对象持有,并且实现了锁的可重入的特性

JVM 中锁具体实现

内存布局中对象头的标记字段(Mark Word)最后两位,用来表示所属对象的锁状态

00代表轻量级锁,01代表无锁或者偏向锁,10代表重量级锁,11 则是 GC算法标志

重量级锁

  1. 传统锁是JVM最基础的锁实现,因为性能开销大,也叫重量级锁
  2. 如何实现: 通过系统内核互斥实现线程阻塞和唤醒
  3. 性能开销大(涉及系统调用,从系统用户态切换到内核态)

锁优化 - 自旋

  1. 自旋锁通过线程轮询锁是否被释放,那么此线程就不会被挂起,而是一直占用着cpu资源
  2. 部分线程的逻辑消耗小于性能调用的消耗时,自旋锁可以避免系统调用的性能消耗(优势)
  3. 占用CPU资源,跑无用指令(期望占用cpu资源时,目标锁资源能够尽快释放)
  4. 默认的自旋次数是10次,超过了限定次数,将会调用内核的方式挂起该线程
  5. 带来了不公平的锁机制,其他阻塞线程,没办法和自旋状态的线程竞争锁资源

自适应自旋

根据以往自旋等待时是否能够获得锁,来动态调整自旋的时间(循环数目)实现自适应自旋
,避免自旋锁可能出现大量浪费处理器资源(轮询锁资源过久,锁仍未释放),自适应意味着自旋时间或次数不再固定

实现原理: 动态调整由前一次在同一个锁上的自旋时间以及持有目标锁资源的线程的状态决定

轻量级锁

'轻量级’只是比较操作系统的传统锁而言,理想应用场景在没有多线程竞争的前提下,减少传统锁的性能开销

实现原理:JVM 通过 CAS 实现轻量级锁

加锁

  1. 进行加锁时,判断锁资源是否为重量级锁
  2. 如果不是,那么会在当前线程(执行到同步代码的线程)中划出一块空间(Lock Record),作为锁的记录,将目标锁对象的标记字段复制到锁记录中
  3. JVM 尝试用 CAS 操作替换目标锁对象的标记字段

1.将目标锁对象的 Mark Word 更新为 Lock Record 的指针
2.更新成功,当前线程持有了该锁对象,失败则代表已被抢先一步抢走了锁,锁对象的Mark Word指针地址被修改了
3.如果被其他线程占有了该锁资源,那么轻量级锁不再有效,膨胀为重量级锁(00–>10),JVM会将锁对象的锁标志变为 ‘10’,等待线程必须进入阻塞状态

解锁

  1. 解锁也是通过 CAS 操作实现
  2. 若锁对象的 Mark Word 仍然指向线程 t 栈帧中的 Lock Record
  3. 借助 CAS 操作将锁对象的 Mark Word 替换为栈帧中复制的 Lock Record:
  4. 替换成功,则解锁成功,线程 t 离开同步块;
  5. 替换失败,说明有其他线程竞争过该锁,锁已经膨胀为重量级锁,唤醒其他阻塞锁

并不是说轻量级锁性能一定比重量级锁好
1. 理想条件:最优情况是大部分锁,是不存在竞争情况的
2. 如果存在有竞争的情况,那么不仅仅是调用系统内核的mutex还要多增CAS操作的损耗

偏向锁

引用场景: 从始至终只有一个线程请求某一把锁,优化掉同步操作消耗的性能

线程进行加锁,如果该锁对象支持偏向锁,那么 JVM 会通过 CAS 操作,将当前线程的地址记录在锁对象的标记字段中,并且将标记字段的最后三位设置为 101(偏向模式:1,最后两位锁状态:01)

之后的运行过程中,每当有线程请求这把锁,Java 虚拟机只需判断锁对象标记字段中:

  1. 最后三位是否为 101
  2. 是否包含当前线程的地址,
  3. 以及 epoch 值是否和锁对象的类的 epoch 值相同

如果都满足,那么当前线程持有该偏向锁,可以直接返回

偏向锁的撤销

当请求锁资源的线程和锁对象标记保持的线程不匹配时,JVM需要撤销偏向锁

  1. 偏向锁的撤销动作必须等待全局安全点;
  2. 暂停拥有偏向锁的线程,判断锁对象是否处于被锁定状态;
  3. 撤销偏向锁,恢复到无锁(标志位为 01)或轻量级锁(标志位为 00)的状态;

如果锁对象总撤销次数超过了阈值(XX:BiasedLockingBulkRebiasThreshold,默认为 20),那么 JVM 会宣布这个资源的偏向锁失效

如果总撤销数超过40次(默认),jvm认为该类不再适合偏向锁,之后的加锁都会转变后轻量级锁

epoch 是什么

某个类的偏向锁失效时,JVM 将该类 epoch 值+1,表示之前epoch值的偏向锁失效

而新设置的偏向锁需要复制新的epoch,为了保证持有锁资源的线程不会丢锁,JVM 需要遍历所有线程的栈,找到该类加锁的实例,并且将他们的 Mark Word中的epoch + 1,该操作需要所有线程处于安全点

参考资料

极客时间-深入理解JVM

synchronized 原理(三):偏向锁、轻量级锁

JVM笔记 - Java 虚拟机关于 Synchronized 实现以及锁实现的总结相关推荐

  1. JVM笔记-java虚拟机

    JVM 常见问题 什么情况下会发生栈内存溢出 谈谈你对jvm的理解?Java8的虚拟机有什么更新? 什么是ooM?什么是stackoverflowerror? jvm的常用参数调优你知道哪些? 谈谈j ...

  2. JVM: java虚拟机

    JVM: java虚拟机 jvm运行我们编写的.java文件转换后的.class文件 问题一 :Class在本地磁盘上 如何记载到jvm中 问题二:jvm又是如何加载java程序所使用的系统类(系统j ...

  3. JVM(Java虚拟机)详解(JVM 内存模型、堆、GC、直接内存、性能调优)

    JVM(Java虚拟机) JVM 内存模型 结构图 jdk1.8 结构图(极简) jdk1.8 结构图(简单) JVM(Java虚拟机): 是一个抽象的计算模型. 如同一台真实的机器,它有自己的指令集 ...

  4. 笔记 | Java 虚拟机

    了解 JVM 一些技术特性的运作原理,让我们写出更适合 JVM 运行和自优化的代码. JVM运行时数据区域 Java 虚拟机(Java Virtual Machine,JVM)在执行 Java 程序过 ...

  5. java jvm目录,JVM(Java虚拟机)中过程工作目录讲解

    JVM(Java虚拟机)中进程工作目录讲解 每次我们用Java命令运行我们的Java程序,都会在JVM中开启一个进程,对于每一个进程,都会有一个相对应的工作目录,这个工作目录在虚拟机初始化的时候就已经 ...

  6. 【JVM】Java虚拟机

    目录 1. 内存区域(运行时数据区) 1.6 常量池 2. 垃圾收集 2.1 什么是垃圾 4. 对象 4.1 对象的创建 1. 内存区域(运行时数据区) 线程私有: 程序计数器.Java虚拟机栈.本地 ...

  7. 读书笔记--Java虚拟机垃圾收集算法

    前言 熟悉虚拟机的垃圾收集算法有助于我们更好的了解Java内存的分配策略.对我来说,以前也有去了解过虚拟机相关的知识点,但是比较零碎.这次拜读<深入理解Java虚拟机>,真是相当后悔自己为 ...

  8. jvm(java虚拟机)线程堆栈jstack(2)

    jstack是java虚拟机自带的一种堆栈查看工具.主要目的是定位线程出现长时间停顿的原因,如线程间死锁.死循环.请求外部资源导致的长时间等待等. jstack -help Usage:jstack ...

  9. 读书笔记——Java虚拟机垃圾收集器与内存分配策略

    本文章已授权微信公众号郭霖(guolin_blog)转载. 本文章讲解的内容是Java虚拟机垃圾收集器与内存分配策略. 概述 说起垃圾收集(Garbage Collection),也就是GC,大部分人 ...

最新文章

  1. Docker 镜像小结---操作指令介绍(七)
  2. IBM将推NVMe存储解决方案
  3. 英伟达_如何超越英伟达?
  4. 现代软件工程讲义 2 开发技术 - 单元测试 amp; 回归测试
  5. 打造TypeScript的Visual Studio Code开发环境
  6. Linux看硬盘同步,从磁盘同步看linux的机制和策略
  7. Flex 页面跳转 四种方法
  8. scrapy爬取动态网页_scrapy_splash 爬取 js 加载网页初体验
  9. Amazon S3 API
  10. em在聊天中是什么意思_被神化的EM菌,该怎样正确使用?
  11. Kinect2.0 vs2013的配置
  12. 博微JAVA面试_博微Java笔试题
  13. 校友故事|我在科大感受理工科“严谨的浪漫主义”
  14. 第三阶段应用层——1.4 数码相册—FreeType介绍
  15. Codeforces Round #322 B Luxurious Houses
  16. 【魔方攻略】五魔方教程(原创)
  17. 时间序列实践(天池大赛)之一
  18. C语言和JAVA的关联
  19. 如何从官网下载MySQL最新版本的安装包?
  20. 全国计算机系统导出名单,墨涩网 - 快速查询导出电脑常用信息——墨涩网

热门文章

  1. 实时游戏对战引擎MatchVS,我的对战旅程
  2. 手把手带你爬天猫,获取杜蕾斯评论数据
  3. 拯救剧荒!程序员最爱看的美剧TOP5!
  4. Unity3D游戏开发介绍
  5. java socket 读取文件_java中ServerSocket读取文件流不是分行读取
  6. 喜茶门店总数超过650家,深圳单城市突破100家店
  7. PTA 7-10 字符转换 (15分)
  8. mongodb添加多条数据_mongodb一次能插入多少数据
  9. HTML / CSS 实践练习
  10. python全栈构图_Python全栈 Web(边框、盒模型、背景)