JVM规范中Synchronized代码块使用monitorentermonitorexit指令实现。Synchronized方法使用另一种方法实现,细节未说明,但同样适用这两个指令实现。
同步代码中,monitorenter被插入开始位置,monitorexit插入到结束处和异常处。传统锁情况下,线程执行到monitorenter时会尝试获取monitor所有权,即尝试获得对象锁,而在monitorexit时解锁。
JSE1.6为了减少获得锁和释放锁的消耗,引入偏向锁和轻量级锁,于是Synchronized对应4种锁状态: 无锁,偏向锁,轻量级锁,重量级锁。偏向锁和轻量级锁Synchronized对应的锁放在Java对象头里1个字长的Mark Word中(相比获取monitor轻量了)。

Note: 以下模型有所简化,只注重原理

Mark Word

32位和64位JavaMark Word长度不一样,但结构基本一致。
Mark Word中最后2bit为锁标志位。
锁标志位11 代表GC标记,标志对象将被清理。
锁标志位01 代表无锁状态/偏向锁,倒数第三位为是否偏向锁标志(1bit),用于区分这两种状态。偏向锁标志为0时为无锁,Mark Word中存放对象的HashCode,分代年龄;偏向锁标志位1时为偏向锁,Mark WordHashCode被替换为持有锁线程的id。
锁标志位00 代表轻量级锁,Mark Word中内容被替换为指向锁记录的指针。
锁标志位10 代表重量级锁,Mark Word中内容被替换为指向互斥量(monitor/mutex)的指针。
由于锁占用了垃圾回收要用的Mark Word位,推测轻量/重量锁对象并不参与垃圾回收。

锁记录

线程进入同步块时,JVM会在当前线程栈桢中创建存储锁记录的空间,并将对象头Mark Word复制到锁记录(如果重入可能填0),这里存储的Mark Word官方称为Displaced Mark Word。线程获取锁时,就会用Displaced Mark Word来进行CAS。线程退出同步块时,栈桢出栈,锁记录消失。

偏向锁

加锁

  1. CAS修改HashCode为当前线程id,成功则获取偏向锁,在栈中添加锁记录,失败则CAS自旋。
  2. CAS失败,检查偏向锁中线程id是否就是当前线程id,如果是则线程已经获取锁。不是则申请撤销偏向锁。

    撤销锁

    只有竞争出现才会撤销偏向锁,撤销执行时机是在全局安全点。

  3. 先检查持有锁的线程是否active,不是active直接撤销。

  4. 当前线程是active则遍历偏向对象的在线程栈中的锁记录,如果当前没有锁记录则撤销,如果有则升级为轻量级锁。

    特点

    偏向锁的引入依据是大多数情况下锁并不存在多线程竞争,偏向锁对同一线程多次锁非常友好,但是对多线程竞争的情况,撤销锁的性能消耗很大。偏向锁默认开启,在应用程序启动几秒之后才激活。
    关闭偏向锁:-XX: UseBiasedLocking = false
    关闭启动延时: -XX: BiasedLocingStartupDelay = 0

    轻量级锁

    加锁

  5. CAS修改Mark Word指向锁记录指针,成功则获得锁,失败表示竞争失败。

  6. CAS失败,则进入CAS自旋。如果有两条或以上线程竞争锁,则膨胀锁为重量级锁。

    解锁

    CASDisplaced Mark Word替换到对象头。如果锁已经被其他线程膨胀为重量级锁,这时Mark Word指向重量级锁指针,导致CAS失败,然后线程会获取重量级锁,并解锁。

    特点

    轻量锁竞争中,竞争锁线程使用自旋而不阻塞,响应速度快。适合每个同步任务速度快的场景。

    重量级锁

    加锁

  7. 如果Mark Word不指向一个monitor对象(当前不是重量级锁),获取或创建一个monitor对象,设置monitorheader字段为Displaced Mark Wordowner字段为Mark Word指向的锁记录指针(轻量锁膨胀时,如果是无锁直接到重量级锁,则为null),obj字段指向锁对象,之后将Mark Word指向monitor

  8. 通过CAS尝试修改monitoronwer字段为锁记录指针,成功则获得锁。否则阻塞,阻塞后加入一个队列中等待解锁唤醒。

    解锁

    monitorowner设置为null,如果等待队列中有其他线程则唤醒。

    特点

    线程竞争不使用自旋,不会消耗CPU,吞吐量优先时使用。

    参考资料

    《Java并发编程的艺术》
    死磕Synchronized底层实现—重量级锁
    JVM锁简介:偏向锁、轻量级锁和重量级锁