Java synchronized锁升级jol过程详解
作者:Katsu 发布时间:2023-04-15 04:58:51
jol(java object layout)需要的依赖
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
一。synchronized锁对象的升级(膨胀)过程主要如下:
1.膨胀过程:无锁(锁对象初始化时)-> 偏向锁(有线程请求锁) -> 轻量级锁(多线程轻度竞争)-> 重量级锁(线程过多或长耗时操作,线程自旋过度消耗cpu);
2.jvm默认延时4s自动开启偏向锁(此时为匿名偏向锁,不指向任务线程),可通过-XX:BiasedLockingStartUpDelay=0取消延时;如果不要偏向锁,可通过-XX:-UseBiasedLocking = false来设置
3.锁只能升级,不能降级;偏向锁可以被重置为无锁状态
4.锁对象头记录占用锁的线程信息,但不能主动释放,线程栈同时记录锁的使用信息,当有其他线程(T1)申请已经被占用的锁时,先根据锁对向的信息,找对应线程栈,若线程已结束,则锁对象先被置为无锁状态,再被T1线程占有后置为偏向锁;若线程位结束,则锁状态由当前偏向锁升级为轻量级锁。
5.偏向锁和轻量级锁在用户态维护,重量级锁需要切换到内核态(os)进行维护;
二。锁对象头(markword部分,8字节)使用不同的状态进行表示,64位虚拟机的markword如下所示:
使用jol演示如下:
1.无锁状态
Object object = new Object(); System.out.println("hash: " + object.hashCode()); System.out.println(ClassLayout.parseInstance(object).toPrintable());
header中前8个字节按照平时习惯的从高位到低位的展示为:00000000 00000000 00000000 00111001 10101110 11101101 00101111 00000001
对照上图,最后3位是001,无锁状态,中间31位(0111001 10101110 11101101 00101111)换算成十进制即为上图打印的hash:967765295
2.匿名偏向锁和偏向锁
Thread.sleep(5000); //等待jvm开启偏向锁
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
synchronized (o){
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
第一次打印为匿名偏向,第二次偏向锁指向了main线程
注意:用run启动程序,不要用debug,实验的时候,用debug启动,第二次打印直接升级轻量级锁。
3.轻量级锁
public static void main(String[] args) throws InterruptedException {
Thread.sleep(5000);
Object o = new Object();
synchronized (o) {
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
for (int i = 0; i < 1; i++) {
Thread t = new Thread(() -> {
print(o);
});
t.start();
}
}
public static void print(Object o) {
synchronized (o){
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
4.重量级锁
public static void main(String[] args){
Object o = new Object();
for (int i = 0; i < 2; i++) {
Thread t = new Thread(() -> {
print(o);
});
t.start();
}
}
public static void print(Object o) {
synchronized (o){
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
来源:https://www.cnblogs.com/katsu2017/p/12610002.html
猜你喜欢
- 在构建RESTful数据服务过程中,我们定义了controller、repositories,并用一些注解修饰它们,但是到现在为止我们还没执
- 主要从以下十几个方面对Hibernate做总结,包括Hibernate的检索方式,Hibernate中对象的状态,Hibernate的3种检
- activity A和BA 获取数据的activity B返回数据的activity点击A上的按钮,在A的textview上显示
- web.xml中设置:<servlet> <servlet-name>DisplayChart</servle
- 前言这里主要简单介绍如何使用Camera+SurfaceView自定义相机拍照,如果是Camera2或者是TextureView的可以前往主
- 获得redis所有的key-value运行结果:redis配置文件需要序列化@Bean public RedisT
- 1、自定义消息转换器MessageConverter在WebMvcAutoConfiguration类中有一个方法configureMess
- 在《Spring Boot Hello World》中介绍了一个简单的spring boot例子,体验了spring boot中的诸多特性,
- 定义在类里面的类就叫做内部类。内部类的特点:在内部类中可以直接访问外部类的成员,包括私有的成员在外部类中不能直接访问内部类的成员,必须通过创
- Java基础面试题及答案集锦(基础题122道,代码题19道),具体详情如下所示:1、面向对象的特征有哪些方面1.抽象:抽象就是忽略一个主题中
- IoC的概念介绍控制反转(IOC)模式(又称DI:Dependency Injection)就是Inversion of Control,控
- 本文实例为大家分享了Android实现双曲线折线图的具体代码,供大家参考,具体内容如下先看一下效果图1.先下载jar包 mpandroidc
- 前言:小伙伴说能不能用springboot整合一下mybatis多数据源不使用JPA进行数据库连接操作。那么说干就干创建一个springbo
- 安装nodejs首先电脑中需要安装nodejs,这个就不多提了,windows就是下载node.exe,一步步安装就可以了。如需安装可参考一
- 打包与运行在项目开发完成之后,可以直接用IDEA将其打包成JAR包运行,也可以打包成WAR包运行以便在多服务器、多配置环境下运行。双击cle
- Java8 HashMap键与Comparable接口最容易使 HashMap 发生哈希冲突的方法是什么呢?我们可以创建一个类,让它的哈希函
- 封面图下个季度的目标是把前端监控相关的内容梳理出来,梳理出来之后可能会在公司内部做个分享~Flutter应用程序既括代码也包括一些其他的资产
- 0.前言HashMap简述:HashMap 基于哈希表的 Map 接口实现,是以 key-value 存储形式存在,即主要用来存放键值对。H
- 返回值转成JSONString的处理主要需求描述有些返回值中的null需要转换成“”或[],另外有些
- 一.方法的基本使用1.什么是方法方法是一个代码片段,类似于C语言中的函数2.方法基本语法基本语法 // 方法定义