zoukankan      html  css  js  c++  java
  • HotSpot虚拟机的锁优化

    面试中多次被问到synchronized关键字的实现原理,一直认为仅是monitorentermonitorexit两条指令而已,原来底层涉及到多种锁优化策略,包括:自旋锁,轻量锁,偏向锁。

    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 recordlock record由一个mark word备份,一个指向对象的指针组成),然后备份当前mark word,最后使用CAS操作把mark word的状态位更新为Thin locked,也就是00,同时mark word中的指针指向lock record

      

    发生重入时,线程可以知道对象mark word中的指针正指向自己的栈,便创建一个值为NULLlock record,在释放锁时如果lock record值为NULL就立即返回。

    当轻量锁被一个线程获得后,另一个希望获取锁的线程会将轻量锁膨胀为重量锁,该线程在一个循环里不断尝试,直到膨胀成功。膨胀也会发生在锁的waitnotify方法被调用时,无论该锁是否已被一个线程获取。

    进行膨胀时,首先用CASmark 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》

  • 相关阅读:
    docker私有仓库搭建及使用
    服务器ip迁移纪要
    Windows 下QT程序发布
    Prometheus监控软件部署方法
    android的listview控件,加了行内按钮事件导致行点击失效的问题
    惊奇!Android studio内部在调用Eclipse
    关于Android Stuido2.3和Eclipse4.4
    XCODE9.1的一些新问题
    osx12.6设置全屏
    IEEE754浮点数与字节数互转工具
  • 原文地址:https://www.cnblogs.com/mmmmar/p/8915558.html
Copyright © 2011-2022 走看看