zoukankan      html  css  js  c++  java
  • synchronized底层实现

     1、锁升级的过程

      当多个线程同时竞争一个对象监视器时:当前对象结构中的mark word中是否是当前线程id,如果是则当前线程获得偏向锁

    如果不是,则通过CAS将当前线程id置换到mark word中,如果成功则获得偏向锁,如果不成功则说明有竞争,升级为轻量级锁。

    后续再通过CAS将线程的指针放到mark word中,若成功则获得锁,否则升级为自旋锁。自旋锁仍然为轻量级锁,不成功升级为重量级锁。

      对象结构:在JVM中,对象在内存中的布局分为三块区域:对象头、实例数据和对齐填充

     mark word:存在于对象头中,存储对象的hashcode,锁标识,分代年龄及GC标识等信息

     由上图可以看出,为何偏向锁是将线程id放入mark word,轻量级锁为何将锁的指针放入mark word。

    偏向锁:指偏向于第一个访问的线程,在运行过程中,同步锁没有竞争,则会在这个线程的头部加一个标志位,标记为偏向锁,如果发生竞争则会升级为轻量级锁或者重量级锁

    自旋锁:线程请求不到对象锁时不会堵塞,只是自己循环一下等待对象锁的释放。因为线程的堵塞和唤醒非常消耗内存,所以自旋锁可以很好的优化这个问题。

    但它只适合等待时间比较短的,而且并发量不高的场景。

    2、升级到重量级锁后,如何运行

     当多线程竞争时,不满足的条件的线程会进入同步队列,满足条件后进入同步代码。在同步代码中执行wait方法,释放对象锁,进入右侧等待队列,当唤醒时 还需要再次获得互斥锁。

    synchronized结构:

      Contention List:竞争队列,所有请求锁的线程首先被放在这个竞争队列中;

      Entry List:Contention List中那些有资格成为候选资源的线程被移动到Entry List中;

       Wait Set:哪些调用wait方法被阻塞的线程被放置在这里;

       OnDeck:任意时刻,最多只有一个线程正在竞争锁资源,该线程被成为OnDeck;

      Owner:当前已经获取到所资源的线程被称为Owner;

      大量并发线程会在contention List中,然后将有资格成为候选的放到entry list中。调用的wait的线程放到wait set中,当被唤醒后会放到entry list中。

    指定EntryList中的某个线程为OnDeck线程(一般是最先进去的那个线程),然后onedeck线程去竞争锁,但是此时其他未进入contention list的线程会先自旋一下看是否能获得到锁,

    所以说synchronied不是公平的。

     当使用synchronized加类锁时,会有严重的效率问题,此时需要考虑是否可以修改为细粒度锁,当修改细粒度锁时,要避免死锁。

    上述若有不对,麻烦各位指正

  • 相关阅读:
    解决nodejs使用yarn安装vue-cli提示'vue' 不是内部或外部命令
    转载——java synchronized详解
    转载——Java中this关键字和super关键字的使用
    转载—— JUnit单元测试教程(翻译自Java Code Geeks)
    Usage and Idioms——Use with Maven
    转载——JUnit 5 新特性
    Usage and Idioms——Categories
    转载——单元测试利器 JUnit 4
    Usage and Idioms——Test Fixtures
    深入JUnit源码之Rule
  • 原文地址:https://www.cnblogs.com/volare/p/12234466.html
Copyright © 2011-2022 走看看