HotSpot虚拟机的锁优化
面试中多次被问到synchronized关键字的实现原理,一直认为仅是monitorenter与monitorexit两条指令而已,原来底层涉及到多种锁优化策略,包括:自旋锁,轻量锁,偏向锁。
1、自旋锁
互斥同步对性能影响最大的部分是线程的阻塞与恢复,因为这两个操作涉及用户态与内核态的转换。如果共享数据锁定时间很短,而且竞争不是特别激烈,那么阻塞实现并不划算。因此在多核的处理器中,我们可以让请求锁的线程进行忙等,而不是放弃处理器执行时间。反之,如果锁占用时间比较长,那忙等的线程只会白白浪费处理器资源,因此需要有一定的时间限制,超出限制便挂起线程。
使用AtomicReference模拟自旋锁:
public class SpinLock { private AtomicReference<Thread> sign =new AtomicReference<>(); public void lock(){
Thread current = Thread.currentThread();
while(!sign .compareAndSet(null, current));
} public void unlock (){
Thread current = Thread.currentThread();
sign .compareAndSet(current, null);
}
}
2、轻量锁
轻量锁是相对于阻塞实现的重量锁而言的,很多时候虽然用到锁,但并不存在竞争情况,相当于多个线程轮流获取一把锁。轻量锁可使用CAS操作获取,被多线程竞争时会膨胀为重量锁。
每个对象的对象头中都有一个字,称为mark word,低两位代表状态,根据状态的不同,其余各位有不同的含义:
HotSpot虚拟机以一种叫做displaced headers的方法实现轻量锁。当线程获取轻量锁时,会在该线程的栈上创建一个lock record(lock record由一个mark word备份,一个指向对象的指针组成),然后备份当前mark word,最后使用CAS操作把mark word的状态位更新为Thin locked,也就是00,同时mark word中的指针指向lock record。
发生重入时,线程可以知道对象mark word中的指针正指向自己的栈,便创建一个值为NULL的lock record,在释放锁时如果lock record值为NULL就立即返回。
当轻量锁被一个线程获得后,另一个希望获取锁的线程会将轻量锁膨胀为重量锁,该线程在一个循环里不断尝试,直到膨胀成功。膨胀也会发生在锁的wait或notify方法被调用时,无论该锁是否已被一个线程获取。
进行膨胀时,首先用CAS将mark word中的状态位更新为Inflating,尝试获取处于该状态锁的线程会等待到膨胀完成,已经获取到锁的线程也必须等到膨胀完成才能释放锁。
3、偏向锁
前文说到轻量锁适合的场景是多个线程轮流占用资源,而偏向锁适用的场景是一个线程反复占用资源。什么时候会出现这种情况呢?比如在使用一些类库时,它的接口是线程安全的,但我们不会通过多个线程访问。
在Unlocked状态下,mark word的第三位代表是否允许启用偏序。如果那一位为0,说明锁没有被任何线程获取,且不允许偏序。如果为1,锁可以是如下状态中的一种:
- 匿名偏向:线程指针为NULL,锁还没有偏向于任何一个线程,这是允许偏向的锁的初始状态。
- 可重偏向:mark word中的epoch字段无效,获取锁的线程可使锁偏向自己。
- 已偏向:线程指针不为NULL,epoch字段有效,锁正偏向于线程指针指向的线程。
由于偏向锁需要占用hashcode字段存放线程指针,访问该对象的hashcode将会导致偏向状态被撤销(Object类的hashcode的方法会导致这种情况)。
偏向锁使用的lock record与轻量锁一致,但是mark word备份没有被使用,在偏向被撤销时,会被转化为轻量锁。
偏序撤销在系统到达全局安全点时执行,竞争线程通过遍历偏序线程的lock record判断锁是否正在被占用, 将其转化为轻量锁或偏向自己。
参考:《Evaluating and improving biased locking in the HotSpot virtual machine》
HotSpot虚拟机的锁优化的更多相关文章
- 深入理解多线程(五)—— Java虚拟机的锁优化技术
本文是<深入理解多线程>的第五篇文章,前面几篇文章中我们从synchronized的实现原理开始,一直介绍到了Monitor的实现原理. 前情提要 通过前面几篇文章,我们已经知道: 1.同 ...
- Java 虚拟机对锁优化所做的努力
作为一款公用平台,JDK 本身也为并发程序的性能绞尽脑汁,在 JDK 内部也想尽一切办法提供并发时的系统吞吐量.这里,我将向大家简单介绍几种 JDK 内部的 "锁" 优化策略. 1 ...
- Java虚拟机对锁优化所做的努力(读书笔记)
锁偏向 是一种加锁操作的优化手段,他的核心思想是:如果一个线程获得了锁,那么就进入偏向模式,当这个线程再次请求锁时,无须在做任何同步操作,因此在几乎没有锁竞争的场合,偏向锁是比较好的优化效果 ...
- Java虚拟机的锁优化
1 锁偏向.当现成请求一个对象锁时,如果获得锁,则该对象锁进入偏向模式,当该线程再次请求该对象的锁时,无需再做任何同步操作. 可通过在Java虚拟机中开启参数-XX:+UseBasedLock开启偏向 ...
- 《深入理解Java虚拟机》-----第13章 线程安全与锁优化
概述 在软件业发展的初期,程序编写都是以算法为核心的,程序员会把数据和过程分别作为独立的部分来考虑,数据代表问题空间中的客体,程序代码则用于处理这些数据,这种思维方式直接站在计算机的角度去抽象问题和解 ...
- 《深入了解java虚拟机》高效并发读书笔记——Java内存模型,线程,线程安全 与锁优化
<深入了解java虚拟机>高效并发读书笔记--Java内存模型,线程,线程安全 与锁优化 本文主要参考<深入了解java虚拟机>高效并发章节 关于锁升级,偏向锁,轻量级锁参考& ...
- Java虚拟机13:互斥同步、锁优化及synchronized和volatile
互斥同步 互斥同步(Mutual Exclusion & Synchronization)是常见的一种并发正确性保证手段.同步是指子啊多个线程并发访问共享数据时,保证共享数据在同一时刻只能被一 ...
- 深入理解java虚拟机(7)---线程安全 & 锁优化
关于线程安全的话题,足可以使用一本书来讲解这些东西.<Java Concurrency in Practice> 就是讲解这些的,在这里 主要还是分析JVM中关于线程安全这块的内容. 1. ...
- 深入理解Java虚拟机读书笔记9----线程完全与锁优化
九 线程完全与锁优化 1 Java语言中的线程完全 ---线程安全:当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用 ...
随机推荐
- 连接池-Mybatis源码
持续更新:https://github.com/dchack/Mybatis-source-code-learn Mybatis连接池 有这么个定律,有连接的地方就有池. 在市面上,可以适配Mybat ...
- 使用BaGet 搭建私有nuget 服务器
使用BaGet 搭建私有nuget 服务器 netNugetBaGet 引言 为了增强代码的安全性和企业团队开发的高效性,搭建私有的package 包管理服务器是很有必要的,搭建私有的类库管理服务有以 ...
- makefile那些事儿
一.好处 自动化编译,一条make命令,整个工程可以完全自动编译,make命令是构建大型项目的首选方案. makefile就像一个shell脚本一样,用来定义规则,一个名称包含一条或多条命令,在终端m ...
- 【NPDP笔记】第一章 新产品开发战略
1.1 战略很重要 1.2 战略定义 使命/愿景/核心价值观:成为领导者 公司/经营战略:市场份额扩大10% 创新战略:强调技术,外部合作 职能战略:IT战略,人力资源战略 1.3明确组织方向 组织身 ...
- linux centos7 安装虚拟Python环境,pyenv安装文档
python多版本控制pyenv安装文档 1.在线安装: curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-i ...
- 安卓学习日记第二天——Fragment
一.基本概念 Fragment是依赖于Activity的,不能独立存在的. 一个Activity里可以有多个Fragment. 一个Fragment可以被多个Activity重用. Fragment有 ...
- 23 Collection集合常用方法讲解
本文讲讲几个Collection的常用方法,这些方法在它的子类中也是很常用的,因此这里先拿出来单独讲解,以后它的子类中的这些方法就不再重复讲解. 几个常用方法: add() 添加一个元素 size() ...
- Linux下使用strip如何对库和可执行文件进行裁减
如果生成的可执行文件或库比较大,这时候就可以使用strip命令进行裁减,在嵌入式开发中,如果使用的交叉编译工具是arm-linux,则命令 是arm-linux-strip,如果是arm-uclibc ...
- golang 之 go-micro
在安装之前首先需要对go-micro有一定的了解 https://micro.mu/docs/cn/ go-micro中文文档 https://juejin.im/post/5cebafe6f265 ...
- JDK和J2EE有什么关系
JDK(Java Development Kit)是Java 开发工具J2EE是Java一个平台 Java 平台有三个版本,这使软件开发人员.服务提供商和设备生产商可以针对特定的市场进行开发:* Ja ...