Java——》synchronized锁升级

推荐链接:

总结------》【Java】

总结------》【Mysql】

总结------》【Redis】

总结------》【Kafka】

总结------》【Spring】

总结------》【SpringBoot】

总结------》【MyBatis、MyBatis-Plus】

总结------》【Linux】

总结------》【MongoDB】

总结------》【Elasticsearch】

Java------》synchronized锁升级

synchronized在jdk1.6之前,一直是重量级锁,只要线程获取锁资源失败,直接挂起线程(用户态切换到内核态),效率低,所以JDK团队在Jdk1.6将synchronized做了3方面优化:锁升级、锁消除、锁膨胀。

锁就是对象,Java中所有对象都是锁。

描述
无锁/匿名偏向 无锁 :没有开启偏向锁(偏向锁延迟开启时间内),没有线程拿锁 匿名偏向:开启偏向锁,没有线程拿锁,没有偏向任何线程
偏向锁 只有一个线程来拿锁资源,没有竞争
轻量级锁 偏向锁出现竞争时,会升级到轻量级锁(触发偏向锁撤销),以CAS的方式(自适应自旋锁)去竞争锁资源,不会让线程挂起。(LockRecord)
重量级锁 直接采用MarkWord指向的ObjectMonitor以传统的方式去竞争锁资源


一、无锁

1、无锁

一般情况下,new出来的一个对象 ,是无锁状态

因为偏向锁有延迟,在启动JVM的4s中,不存在偏向锁。

2、匿名偏向

如果关闭了偏向锁延迟的设置,new出来的对象,就是匿名偏向,但没有偏向任何线程。

java 复制代码
//关闭延迟开启偏向锁
-XX:BiasedLockingStartupDelay=0
//4s之后开启偏向锁
-XX:BiasedLockingStartupDelay=4

//禁止偏向锁
-XX:-UseBiasedLocking 
//启用偏向锁
-XX:+UseBiasedLocking 

二、偏向锁

没有线程的竞争,只有一个线程在获取锁资源。

1、获取锁资源的过程(锁升级过程)

当某一个线程来获取这个锁资源时,发现没有线程占用锁资源,并且锁是偏向锁,使用CAS的方式,设置对象的线程ID为当前线程,获取到锁资源,下次当前线程再次获取锁资源时,只需要判断是偏向锁,并且对象的线程ID是当前线程ID就直接获得到锁资源。如果对象的线程ID不是当前线程ID,也就是说偏向锁状态出现了锁竞争的情况,就触发锁升级,升级为轻量级锁。

2、为什么要有偏向锁延迟

JVM在启动时,需要加载大量的.class文件到内存中,这个操作会涉及到synchronized的使用,为了避免出现偏向锁撤销导致启动效率变慢,所以JVM启动时,有一个延迟4s开启偏向锁的操作。

偏向锁是延迟开启的,并且在开启偏向锁之后,默认不存在无锁状态,只存在匿名偏向。

3、为什么偏向锁撤销会导致启动变慢

当偏向锁升级到轻量锁时,会触发偏向锁撤销

(1)偏向锁撤销需要等到一个安全点 (STW),才可以做偏向锁撤销。

(2)偏向锁撤销的成本太高(消耗资源)

4、偏向锁撤销安全点

  • GC
  • 方法返回之前
  • 调用某个方法之后
  • 抛出异常的位置
  • 循环的末尾

5、偏向锁重入

用到了LockRecord,只不过内部不会存储hashcode信息等等,在偏向锁重入时,每次都会压栈一个LockRecord,从而实现偏向锁重入。

6、偏向锁会降级到无锁状态吗以及如何降

会。

当偏向锁状态下,获取当前对象的hashcode值,会因为对象头空间无法存储hashcode,导致降级到无锁状态。

三、轻量级锁

如果出现了多个线程的竞争 ,就要升级为轻量级锁 (有可能直接从无锁变为轻量级锁,也有可能从偏向锁升级为轻量级锁,会触发偏向锁撤销)。

轻量级锁的是基于CAS 尝试获取锁资源,这里会用到自适应自旋锁,JVM会自动的根据上次CAS成功与否,决定这次自旋多少次。

  • 如果成功获取到,拿着锁资源走
  • 如果自旋了一定次数,没拿到锁资源,锁升级为重量级锁

四、重量级锁

轻量级锁CAS一段次数后,没有拿到锁资源,升级为重量级锁。线程拿不到锁,就挂起。

java 复制代码
public static void main(String[] args) throws InterruptedException {
    Thread.sleep(5000);
    Object o = new Object();
    System.out.println(ClassLayout.parseInstance(o).toPrintable());

    new Thread(() -> {

        synchronized (o){
            //t1  - 偏向锁
            System.out.println("t1:" + ClassLayout.parseInstance(o).toPrintable());
        }
    }).start();
    //main - 偏向锁 - 轻量级锁CAS - 重量级锁
    synchronized (o){
        System.out.println("main:" + ClassLayout.parseInstance(o).toPrintable());
    }
}

1、重量级锁会降级到偏向锁或者是轻量级锁吗

不会

2、如何竞争锁资源

直接采用MarkWord指向的ObjectMonitor以传统的方式去竞争锁资源

相关推荐
北漂老男孩15 分钟前
Flink基于Yarn多种启动方式详解
java·大数据·flink
王蛋11116 分钟前
后端环境配置
java·spring·maven
养-乐多17 分钟前
梳理Spring Boot中三种异常处理
java·spring boot·后端
找不到、了21 分钟前
字符串和常量池的进一步研究
java·开发语言
Code哈哈笑26 分钟前
【基于SpringBoot的图书购买系统】深度讲解 分页查询用户信息,分析前后端交互的原理
java·数据库·spring boot·后端·spring·交互
kingwebo'sZone31 分钟前
sqlite的拼接字段的方法(sqlite没有convert函数)
java·数据库·sqlite
星沁城34 分钟前
212. 单词搜索 II
java·数据结构·算法·leetcode
.生产的驴1 小时前
Vue3 数据可视化屏幕大屏适配 页面自适应 响应式 数据大屏 大屏适配
java·c++·vue.js·后端·信息可视化·前端框架·vue
龙泉寺天下行走1 小时前
《进化陷阱》--AI 生成文章 《连载 1》
java·服务器·前端
王小义笔记1 小时前
使用注解动态映射:根据实体List列表动态生成Excel文件
java·数据结构·list·excel·poi