美文网首页
Synchronized的实现原理与应用。

Synchronized的实现原理与应用。

作者: 西瓜真好吃丶 | 来源:发表于2018-07-16 11:43 被阅读0次

    在javaSE1.6中对Synchronized进行了大量的优化,使一个笨重的锁变得灵活了起来。
    在讲Synchronized之前,要先介绍一下java的对象头:

    • 在32位的虚拟机中,java对象头使用25bit存储对象的hashCode,用4bit存储对象的分代年龄,用1bit来判断是否是偏向锁,再用2bit来存储锁的标志位。(00为轻量级锁 01为偏向锁 11为GC标记 10为重量级锁)
    • 在64位的虚拟机中,无锁的时候,25bit不用,31bit用来存储hashCode,1bit用来存储cms_free,4bit存储分代年龄,1bit判断是否为偏向锁,2bit存储锁的标志位。在有锁时,前56位中(54bit存储线程ID,2bit存储Epoch)

    从上面可以看出,共同点是都有3个bit给锁使用。
    得出结论:java中的每一个对象都可以作为锁。

    Synchronized的三种用法:

    • 对于普通同步方法,锁是当前实例对象。
    • 对于静态同步方法,锁是当前类的Class对象。
    • 对于同步方法块,锁是Sychronized括号里配置的对象。

    在javaSE1.6中锁一共有4种状态:无锁、偏向锁、轻量级锁、重量级锁。
    下面把锁转换的流程说一遍:
    当一个线程访问同步代码块并获取锁的时候,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID。当该线程再次进入同步代码块时,只需判断对象头的Mark World里是否存储着指向当前线程的偏向锁。
      如果成功,则表示已获得了锁,直接进入。
      如果失败,则再判断该mark world中的锁标识是否为偏向锁。
         如果该锁标识为偏向锁则进行偏向锁的竞争。
         如果该锁标识不为偏向锁,则进行对应锁的竞争。

    偏向锁的竞争及升级过程:
      1.线程2来竞争锁对象
      2.判断拥有偏向锁的线程1是否还存在
      3.如果线程1不存在,则设置偏向锁标识为0
      4.用cas操作替换锁线程ID为线程2,锁不升级,仍然为偏向锁。
      5.线程1仍然存在,暂停线程1;
      6.设置锁的标志位为00,偏向锁标识为0,升级为轻量级锁。
      7.在线程1的栈帧中创建用于存储锁记录的空间,并将对象头中的MarkWorld复制到锁记录中。
      8.继续执行线程1的代码。
      9.线程2进行自旋操作获得轻量级锁。

    轻量级锁升级:
      1.如果线程2自旋后获取锁失败,或者在线程2自旋的时候,线程3也来获取锁,那么该锁会升级为重量级锁。当锁处于这个状态下时,其他线程试图获取锁时都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进行新一轮的竞争。

    相关文章

      网友评论

          本文标题:Synchronized的实现原理与应用。

          本文链接:https://www.haomeiwen.com/subject/jevvpftx.html