美文网首页Java实战技术
高并发编程-锁优化

高并发编程-锁优化

作者: JavaQ | 来源:发表于2018-11-13 21:02 被阅读0次

Java在语言上支持了锁的特性,在很多常用类的实现中也使用了锁,对于Java开发者来说就可以很方便的使用这些锁及常用类。但是,随着锁的频繁使用及错用,随之而来的就是程序执行效率变低、应用变的缓慢。为了提高线程对共享数据访问的效率,HotSpot虚拟机从JDK1.5到JDK1.6做了重大改进,提供了很多锁优化技术,包括自旋锁、自适应自旋锁、锁消除、锁粗化、轻量级锁和偏向锁。

自旋锁

线程的执行是通过竞争获取处理器的执行时间才执行的。当线程挂起或恢复执行的时,会从用户态转入内核态中完成,这种操作是很消耗时间的,在并发情况下对应用和系统来说都有很大压力。HotSpot虚拟机的开发人员注意到很多应用对共享数据锁定的时间都是很短暂的,为了这短暂的时间而挂起和恢复线程是不值得的。所以,线程并发请求锁的时候,让后来的线程在不放弃处理器执行时间的情况下稍等一下,线程做自旋,自旋期间观察持有锁的线程是否会很快释放锁,这种技术就是所谓的自旋锁。

自旋锁在JDK1.6中是默认开启的,默认自旋次数是10次,可以使用参数-XX:PreBlockSpin修改默认值。虽然,自旋锁避免了线程挂起和恢复的开销,但是它占用了处理器的执行时间,如果锁占用时间很短,自旋锁效果很好,否则会浪费处理器的执行时间,影响应用的整体性能。

自适应自旋锁

在JDK1.6中引入了自适应自旋锁,自旋的次数由上一次在同一个锁上自旋的时间和锁持有者的状态来决定。如果上一次同一个锁通过自旋刚刚被获取,并且持有锁的线程正在运行,那么虚拟机认为本次自旋也会成功,将会自旋相对长的时间获取锁。如果同一个锁很少通过自旋成功被获取,那么虚拟机认为本次自旋也会失败,不会执行自旋操作。

锁消除

一些使用了锁控制的代码,在虚拟机即时编译器运行时检测到不存在对共享数据的竞争访问,也就是代码只会被一个线程访问,此时会对锁进行消除,这项优化称为锁消除。锁消除的主要判断依据来源于逃逸分析(即分析对象的动态作用域,一个对象在方法内被定义后,在别的方法或线程中无法通过任何途径访问到这个对象,则可以进行一些优化操作)的数据支持。

锁粗化

大多数情况下,为了提高程序的执行效率,会缩小锁作用的范围。但是,对于一些连续操作都对同一个对象进行反复加锁、释放锁的情况来说,缩小锁的作用范围会消耗更多的资源,这种情况需要扩大锁的作用范围,这项优化称为锁粗化。

轻量级锁

了解轻量级锁之前,先了解一下Java对象在内存中存储的数据结构。在HotSpot虚拟机中,Java对象在内存中存储的布局分为3块区域:对象头、实例数据和对齐填充。对象头包含两部分,第一部分包含对象的HashCode、分代年龄、锁标志位、线程持有的锁、偏向线程ID等数据,这部分数据的长度在32位和64位虚拟机中分别为32bit和64bit,官方称为Mark World。考虑到虚拟机的空间效率,Mark World内部的数据结构是非固定的,也就是说对象头中存储的内容是不固定的,下图展示了不同状态下,对象头中存储的内容:

Mark-World (1).png

当代码执行到同步代码时,如果此时对象的锁未被锁定(锁标志位位01),虚拟机将在当前线程的栈帧中创建一个名为Lock Record空间,这个空间用于存储当前对象的Mark World拷贝,具体如下图所示。

lock-record-1.png

接着,虚拟机使用CAS尝试将对象的对象头Mark Wolrd指向Lock Record,也就是在Mark Wolrd的30bit存储Lock Record的起始地址,具体如下图所示。如果上述操作执行成功,当前线程就持有了对象的锁,此时对象处于轻量级锁锁定状态,对应的锁标志位为00。

lock-record-2.png

如果上述操作执行失败,首先会检查对象的对象头Mark World是否指向了当前线程栈帧中的Lock Record,如果指向了则表示当前线程已经持有了对象的锁,否则表示对象的锁已经被其它线程持有,锁膨胀为重量级锁,线程挂起等待。

轻量级锁的释放过程,通过CAS将Lock Record中存储的Mark Wolrd拷贝替换回对象的对象头Mark Wolrd中,替换成功则锁释放成功,否则表示有其它线程尝试获取过锁,释放锁的同时,唤醒挂起的线程,这里笔者的理解是此时锁膨胀为重量级锁,唤醒等待线程竞争。

偏向锁

锁对象第一次被线程持有的时候,虚拟机通过CAS把获取到这个锁的线程ID记录到对象头Mark World中,操作成功则成功获取偏向锁,对象头中的锁标志位设置为01。持有偏向锁的线程每次执行到这段同步代码时,不需要任何同步操作,这项优化称为偏向锁。

当有其它线程尝试获取对象的锁时,终止偏向模式,同时根据锁是否处于锁定状态,撤销偏向锁恢复到未锁定或轻量级锁状态。

END

如果觉得有收获,记得关注、点赞、转发。

image

相关文章

  • 高并发编程-锁优化

    Java在语言上支持了锁的特性,在很多常用类的实现中也使用了锁,对于Java开发者来说就可以很方便的使用这些锁及常...

  • 高并发

    分布式 cache 事件驱动-异步处理 高并发编程【锁优化篇】https://zhuanlan.zhihu.com...

  • java并发

    1.并发编程中的锁 并发编程中的各种锁java高并发锁的3种实现Java并发机制及锁的实现原理 2.线程池核心线程...

  • 深入了解Synchronized同步锁的优化方法

    多线程之锁优化(上):深入了解Synchronized同步锁的优化方法 在并发编程中,多个线程访问同一个共享资源时...

  • 高并发秒杀API(六)

    前言 本篇将完成高并发优化,包括: Redis后端缓存优化 并发优化 一、高并发优化分析 在优化之前要明白高并发发...

  • Java并发编程-锁优化

    参考资料:《实战Java高并发程序设计》 1.锁优化的几个方面 1.减少锁持有时间 减少锁的持有时间有助于降低锁冲...

  • 并发编程-锁的优化

    上一篇 <<<锁的深入化[https://www.jianshu.com/p/842839f43ee0]下一篇 >...

  • Java并发编程 - 锁优化

    此图为网上收集来的,若有侵权,请私信告知。

  • Java高并发容器

    JUC基于非阻塞算法(Lock Free,无锁编程)提供了一组高并发容器,包括高并发的List、Set、Queue...

  • JAVA并发编程与高并发解决方案 - 并发编程 二 之 线程安全

    JAVA并发编程与高并发解决方案 - 并发编程 二 相关文章 JAVA并发编程与高并发解决方案 - 并发编程 一 ...

网友评论

    本文标题:高并发编程-锁优化

    本文链接:https://www.haomeiwen.com/subject/thkrfqtx.html