• 技术文章 >Java >java教程

    Java中synchronized锁的升级过程是什么?

    WBOYWBOY2023-04-21 16:19:19转载29

    synchronized锁是啥?锁其实就是一个对象,随便哪一个都可以,Java中所有的对象都是锁,换句话说,Java中所有对象都可以成为锁。
    这次我们主要聊的是synchronized锁升级的套路

    synchronized会经历四个阶段:无锁状态、偏向锁、轻量级锁、重量级锁依次从耗费资源最少,性能最高,到耗费资源多,性能最差。

    锁原理

    先看看这些状态的锁为什么称之为锁,他们的互斥原理是啥。

    偏向锁

    当一个线程到达同步代码块,尝试获取锁对象的时候,会查看对象头中的MarkWord里的线程ID,如果这里没有ID则将自己的保存进去,拿到锁。若是有,则查看是否是当前线程,如果不是,就CAS尝试改,如果是,就已经拿到了锁资源。

    这里详细说说CAS尝试修改的逻辑:它会检查持有偏向锁的线程状态。首先遍历当前JVM的所有存活的线程,如果能找到偏向的线程,则说明偏向的线程还存活,此时会检查线程是否在执行同步代码块中的代码,如果是,则升级为轻量级锁,去继续进行CAS竞争锁。所以加了偏向锁之后,同时只有一个线程可以拿到锁执行同步代码块中的代码。

    轻量级锁

    查看对象头中的MarkWord里的Lock Record指针指向的是否是当前线程的虚拟机栈,如果是,拿锁执行业务,如果不是则进行CAS,尝试修改,若是修改几次都没有成功,再升级到重量级锁。

    重量级锁

    查看对象头中的MarkWord里的指向的ObjectMonitor,查看owner是否是当前线程,如果不是,扔到ObjectMonitor里的EntryList中排队,并挂起线程,等待被唤醒。

    锁升级

    无锁

    一般情况下,新new出来的一个对象,暂时就是无锁状态。因为偏向锁默认是有延迟的,在启动JVM的前4s中,不存在偏向锁,但是如果关闭了偏向锁延迟的设置,new出来的对象,就会添加一个匿名偏向锁。也就是说这个对象想找一个线程去增加偏向锁,但是没有找到,称之为匿名偏向。存储的线程ID为一堆0000,也没有任何地址信息。

    我们可以通过以下配置关闭偏向锁延迟。

    //关闭偏向锁延迟的指令
    -XX:BiasedLockingStartuoDelay=0

    偏向锁

    当某一个线程来获取这个锁资源时,此时会成功获取到,就会变为偏向锁,偏向锁存储线程的ID。

    偏向锁升级时,会触发偏向锁撤销,偏向锁撤销需要等到一个安全点,比如GC的时候,偏向锁撤销的成本太高,所以默认开始时,会做偏向锁延迟。若是直接有多个线程竞争,会跳过偏向锁,直接变为轻量级锁。

    细说一下偏向锁撤销的过程,成本为啥高呢?当一个线程拿到偏向锁之后,会把锁的对象头的Mark Work中的线程id指向自己,当又有一个线程来了进行争抢导致锁升级的的时候,会暂停之前拿到偏向锁的线程,然后清空Mark Work中的线程id增加一个轻量级锁,然后再恢复暂停的线程继续执行。这也是为什么等到安全点再执行锁升级的原因,因为要暂停线程。

    常见的安全点:

    轻量级锁

    当在出现了多个线程的竞争,就会升级为轻量级锁,轻量级锁的效果就是基于CAS尝试获取锁资源,这里会用到自适应自旋锁,根据上次CAS成功与否,耗费的时间,决定这次自旋多少次。

    轻量级锁适用于竞争不是很激烈的场景,一个线程拿到锁,执行同步代码块,很快就处理完了。再来一个线程尝试一两次也拿到了锁,再去执行,不会让一个线程等待很久。

    重量级锁

    如果到了重量级锁,那就没啥说的了,如果有线程持有锁,其他想拿锁的就挂起,等待锁释放后被依次唤醒

    锁粗化&锁消除

    锁粗化/锁膨胀

    锁膨胀是编译Java文件的时候,JIT帮我们做的优化,它会减少锁的获取和释放次数。 比如:

    while(){
       synchronized(){
          // 多次的获取和释放,成本太高,会被优化为下面这种
       }
    }
    synchronized(){
       while(){
           //  拿到锁后执行循环,只加锁和释放一次
       }
    }

    锁消除

    锁消除则是在一个加锁的同步代码块中,没有任何共享资源,也不存在锁竞争的情况,JIT编译时,就直接将锁的指令优化掉。 比如

    synchronized(){
       int a = 1;
       a++;
       //操作局部变量的逻辑
    }

    以上就是Java中synchronized锁的升级过程是什么?的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:亿速云,如有侵犯,请联系admin@php.cn删除
    专题推荐:Java synchronized
    上一篇:Java 项目工程实例代码分析 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • java泛型接口的使用注意事项是什么• java如何求数值型数组中元素的最大值、最小值、平均数、总和等操作• java如何通过字节流实现文件的拷贝• java中wait调用中断怎么解决• Java设计模式的适配器模式怎么实现
    1/1

    PHP中文网