Mark Word

谈JVM的同步机制,不得不先了解一下Java对象头中的Mark Word,JVM同步的实现离不开这个数据结构。

存储内容标记状态
hash、对象分代年龄01无锁
指向(虚拟机栈中)锁记录地址的指针00轻量级锁
指向操作系统重量级锁的指针10重量级锁
forwarding指针11GC标记
偏向线程ID、对象分代年龄01偏向/可偏向锁

锁的类型

重量级锁(heavy-weight locking)

操作系统级别的锁机制,包括互斥(mutex)对象和条件变量(condition variables)

轻量级锁(light-weight locking)

所有现代JVM都引入了经量级锁:

  • 避免将每个对象关联操作系统的重量级锁
  • 当不存在锁竞争时,使用原子操作来进入退出同步块
  • 如果发生锁竞争,回退到操作系统的重量级锁

使用轻量级锁会提高效率,因为大部分锁都不存在竞争。

具体实现

 

上图描述了标准的加锁过程:

  1. 开始对象处于未锁定状态。
  2. 当在对象上进行同步时,mark word被拷贝到当前线程栈帧上的锁记录(lock record,用于追踪被当前线程锁定的对象)中,它被称之为displaced mark。
  3. 线程使用原子的CAS(Compare-and-swap)指令尝试将mark word的指针指向帧栈上的锁记录。
  4. 若CAS成功,则该线程获得锁。
  5. 若CAS失败,则轻量级锁膨胀为重量级锁以管理等待线程。

由于在多处理器上执行原子的CAS操作代价是昂贵的,大多数锁不仅不存在竞争,它们还通常由同一个线程重复加锁/解锁。为了解决这些问题,引入了偏向锁(Biased Locking),只有第一次获取锁时,使用CAS操作将线程ID置于对象头的mark word中 。这个对象会偏向于第一次获取锁的线程,之后该线程锁定和解锁对象不需要任何原子操作或mark word的更新。若另外的一个线程锁定了该对象,则取消偏向。

总结

轻量级锁在使用操作系统重量级锁之前,首先进行CAS操作以减少系统开销,因为大部分锁都是无竞争的。

偏向锁的目的是无竞争的时候连CAS操作都不需要,直接使用偏向线程。

参考

https://wiki.openjdk.java.net/display/HotSpot/Synchronization

https://www.cs.princeton.edu/picasso/mats/HotspotOverview.pdf

https://en.wikipedia.org/wiki/Monitor_(synchronization)

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.