JVM锁优化

1.锁优化

  • 挂起线程和恢复线程的开销较大,对于锁定状态时间较短的情况下,挂起线程并不值得。
  1. 自旋锁与它的自适应自旋

    • 遇到锁不会挂起,而是忙循环(自旋)一会儿,避免了一次线程切换的开销,但是仍在占用CPU时间。
    • 1.6默认开启,默认自旋10次。
    • 1.6还引入了自适应自旋锁,他可以根据上一次在同一个锁上的自旋时间调整自旋次数。
    • 自旋失败则进入正常的挂起线程。
  2. 锁消除
    • JIT即时编译器在运行时如果发现某块代码上有同步,但是检测到该共享区域不可能存在竞争,就会进行锁消除。
    • 如对某个局部变量操作时加了锁,但是局部变量不可能逃逸出方法,所以2个线程不可能对同一个局部变量存在竞争。此时就会消除锁。
    • JIT编译说明这段代码是热点代码,消除锁之后对性能提高有所帮助。
  3. 锁粗化
    • 对一个对象反复的加锁解锁。如StringBuff的append()方法,编译器会优化到最外面一个锁。
  4. 轻量级锁
    • jvm实现无竞争情况下使用CAS操作消除同步使用的互斥量。
    • 轻量级锁为什么可以提高性能就是因为 “绝大多数部分的锁在整个同步周期内都是不存在竞争的”,这是一个经验数据,如果不存在竞争使用CAS操作就可以避免使用同步互斥量的开销。
  5. 偏向锁
    • 轻量级锁是无竞争情况下使用CAS操作取消使用同步互斥量,而偏向锁是无竞争情况下取消整个同步,连CAS都不用做。
    • 偏向锁会偏向第一个获得他的线程,如果该锁没有被其他线程获取,那么持有偏向锁的线程就不会进行同步。

2.对象头

  • 我们所说的某个对象的锁其实就是该对象的对象头中的几个标志位,该标志位改变为某个值说明该对象的锁被线程拿走了,释放锁后标志位恢复。
  • 对象头分为2部分,第一部分存储对象自身运行时数据,第二部分存储类型指针。
  1. 自身运行时数据(Mark Word):如哈希码、GC分代年龄、锁转态标志、线程持有的锁,偏向线程ID、偏向时间戳。Mark Word是非固定的数据结构,以便存储更多信息,根据对象状态不同各个信息所占位数会变化,但总体肯定是8字节倍数。32位机下Mark Word占32bit,64位机下占64bit。
  2. 类型指针:指向元数据(Class类数据)的指针
  3. 如果对象是数组那么对象头还有一块用于记录数组长度的区域,因为普通Java对象通过元数据可以确定大小,而数组的元数据无法确定数组大小。

2.1 Mark Word 的不同状态下存储不同内容。

状态 标志位 存储内容
未锁定 01 对象哈希码。对象分代年龄
 轻量级锁定  00 指向锁记录的指针
膨胀(重量级锁定)  10  指向重量级锁的指针 
GC标记  11  空,不需要记录信息 
可偏向  01  偏向线程ID、偏向时间戳、对象分代年龄 

2.2 不同状态下不同信息所占的位数和位置

3.轻量级锁的实现和加锁过程。

  • 程序并不是一遇到同步代码块立刻就拿到对象的重量级锁。
  1. 加锁

    1. 代码进入同步块时如果锁对象的标志位时01那么虚拟机会在当前线程的栈帧中建立一个 锁记录 空间 Lock Record,用来存储锁对象目前的Mark Word 的拷贝。
    2. 然后执行CAS 操作 ,它会比较锁对象的Mark Word 与拷贝是否相等。如果相等执行3,如果不等执行5
    3. 如果相等将锁对象的Mark Word 中的存储内容替换为 指向栈帧中拷贝的指针,此时这个线程就获得了该对象的锁,并且对象的锁标志位改为00。
    4. 此时栈帧中的Mark Word 存储的内容是(对象的hashCode,分代年龄,偏向锁位)而锁对象Mark Word 存储的内容是(指向栈中锁记录的指针),而且前者锁标志位01,后者锁标志位00.
    5. 如果不相等首先检查锁对象Mark Word内容是否指向当前线程,如果指向执行6,如果没有指向执行7
    6. 如果指向说明当前线程已经拿到了锁,则可以进入同步代码块执行,比如同步方法中调用同步方法,并且使用的同一个锁对象。
    7. 如果没有指向当前线程说明锁已经被别的线程拿到了,此时锁标志位改为10,锁对象Mark Word内容换为指向互斥量(重量级锁synchronized)的指针,然后执行8
    8. 注意此时线程发现拿不到锁也不会立刻被挂起,它会加入自旋,如果自旋一定次数失败就会进入阻塞状态。
  2. 解锁

    1. 首先查看锁对象的Mark Word内容是否指向栈,如果是那么就交换两者,同步代码执行完成。
    2. 如果没有,说明有别的线程来拿过锁,所以要解除互斥量同时唤醒被挂起的线程。
    3. synchronized是不公平的不会按先后挂起顺序唤醒。

4.偏向锁

  1. -XX:+UseBiasedLocking 启用偏向锁,1.6默认
  2. 锁对象第一次被线程获得,会把标志位设为01,此时线程ID还是空,对象还未锁定
  3. 通过一次CAS操作会把获取到这个锁对象的线程ID存入锁对象的Mark Word。此时对象已被锁定。
  4. 之后持有偏向锁的线程进入同步代码就不需要任何同步操作了。
  5. 如果另一个线程来获取锁,那么偏向模式就结束,分别如图按2种不同情况作出不同反应。

原文地址:https://www.cnblogs.com/mibloom/p/9613598.html

时间: 2024-10-12 03:05:47

JVM锁优化的相关文章

锁优化

[JVM锁优化:http://www.importnew.com/15340.html] [自旋锁] 互斥同步对性能最大的影响是阻塞的实现,挂起线程和恢复线程的操作都需要转入内核态中完成,这些操作给系统的并发性能带来了很大的压力.而在很多应用上, 共享数据的锁定状态只会持续很短的一段时间.若实体机上有多个处理器,能让两个以上的线程同时并行执行,我们就可以让后面请求锁的那个线程原地自旋(不放 弃CPU时间),看看持有锁的线程是否很快就会释放锁.为了让线程等待,我们只须让线程执行一个忙循环(自旋),

jvm(13)-线程安全与锁优化(转)

0.1)本文部分文字转自“深入理解jvm”, 旨在学习 线程安全与锁优化 的基础知识: 0.2)本文知识对于理解 java并发编程非常有用,个人觉得,所以我总结的很详细: [1]概述 [2]线程安全 1)线程安全定义:当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的:(干货——线程安全定义) [2.1]java 语言中的线程安全(干货——java

使用ZooKeeper实现Java跨JVM的分布式锁(优化构思)

说明:这篇文章是基于 使用ZooKeeper实现Java跨JVM的分布式锁 的,没有阅读的朋友请先阅读前面的文章后在阅读本文. 上一篇文章中介绍了如何使用分布式锁,并且对原来的公平锁进行了扩展,实现了非公平锁,已经能够满足大部分跨进程(JVM)锁的需求了. 问题:我们都知道在单个JVM内部实现锁的机制很方便,Java也提供了很丰富的API可以实现,例如Synchronized关键字, ReentrantLock等等,但是在集群环境中,都是多个JVM协同工作,当需要一些全局锁时就要用到上面介绍的分

java源码剖析: 对象内存布局、JVM锁以及优化

一.目录 1.启蒙知识预热:CAS原理+JVM对象头内存存储结构 2.JVM中锁优化:锁粗化.锁消除.偏向锁.轻量级锁.自旋锁. 3.总结:偏向锁.轻量级锁,重量级锁的优缺点. 二.启蒙知识预热 开启本文之前先介绍2个概念 2.1.cas操作 为了提高性能,JVM很多操作都依赖CAS实现,一种乐观锁的实现.本文锁优化中用到了CAS,故有必要先分析一下CAS的实现. CAS:Compare and Swap. JNI来完成CPU指令的操作: unsafe.compareAndSwapInt(thi

Java锁优化思路及JVM实现

1. 锁优化的思路和方法 这里提到的锁优化,是指在阻塞式的情况下,如何让性能不要变得太差.但是再怎么优化,一般来说性能都会比无锁的情况差一点. 这里要注意的是,在ReentrantLock中的tryLock,偏向于一种无锁的方式,因为在tryLock判断时,并不会把自己挂起. 锁优化的思路和方法总结一下,有以下几种. 减少锁持有时间 减小锁粒度 锁分离 锁粗化 锁消除 #### 1.1 减少锁持有时间 public synchronized void syncMethod(){ othercod

一夜搞懂 | JVM 线程安全与锁优化

前言 本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍: 我的 GIthub 博客 学习导图 一.为什么要学习内存模型与线程? 之前我们学习了内存模型和线程,了解了 JMM 和线程,初步探究了 JVM 怎么实现并发,而本篇文章,我们的关注点是 JVM 如何实现高效 并发编程的目的是为了让程序运行得更快,提高程序的响应速度,虽然我们希望通过多线程执行任务让程序运行得更快,但是同时也会面临非常多的挑战,比如像线程安全问题.线程上下文切换的问题.硬件和软件资源限制等问题,这些都是并发编程

JVM中锁优化,偏向锁、自旋锁、锁消除、锁膨胀

详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt364 本文将简单介绍HotSpot虚拟机中用到的锁优化技术. 自旋锁 互斥同步对性能最大的影响是阻塞的实现,挂起线程和恢复线程的操作都需要转入内核态中完成,这些操作给系统的并发性能带来了很大的压力.而在很多应用上,共享数据的锁定状态只会持续很短的一段时间.若实体机上有多个处理器,能让两个以上的线程同时并行执行,我们就可以让后面请求锁的那个线程原地自旋(不放弃CPU时间),看

[转载]深入JVM锁机制-synchronized

转自:http://blog.csdn.net/chen77716/article/details/6618779,并加上少量自己的理解 目前在Java中存在两种锁机制:synchronized和Lock,Lock接口及其实现类是JDK5增加的内容,其作者是大名鼎鼎的并发专家Doug Lea.本文并不比较synchronized与Lock孰优孰劣,只是介绍二者的实现原理. 数据同步需要依赖锁,那锁的同步又依赖谁?synchronized给出的答案是在软件层面依赖JVM,而Lock给出的方案是在硬

深入JVM锁机制1-synchronized

http://blog.csdn.net/chen77716/article/details/6618779 目前在Java中存在两种锁机制:synchronized和Lock,Lock接口及其实现类是JDK5增加的内容,其作者是大名鼎鼎的并发专家Doug Lea.本文并不比较synchronized与Lock孰优孰劣,只是介绍二者的实现原理. 数据同步需要依赖锁,那锁的同步又依赖谁?synchronized给出的答案是在软件层面依赖JVM,而Lock给出的方案是在硬件层面依赖特殊的CPU指令,