JAVA锁

62 阅读2分钟

对象头结构

Java对象头主要包含了以下信息:

  1. Mark Word:用于存储对象的hashCode、锁状态标志、线程持有的锁、偏向线程ID、自旋锁计数等。
  2. Class Metadata Address:指向对象的类元数据信息。
  3. Array Length:如果对象是数组,那么这里存储数组的长度。

锁状态变化过程

  1. 无锁状态:初始状态,对象头中不包含锁信息。
  2. 偏向锁:当线程首次访问同步块并成功获取锁时,会将对象头中的Mark Word设置为偏向锁状态,并记录获取锁的线程ID。后续该线程再次访问时,无需进行CAS操作即可快速获取锁。
  3. 轻量级锁:如果另一个线程尝试访问已被偏向锁锁定的同步块,那么偏向锁会升级为轻量级锁。此时,会通过CAS操作尝试获取锁。如果获取失败,该线程会自旋等待(自旋锁),直到获取锁为止。如果自旋等待超过一定次数或时间,轻量级锁会升级为重量级锁。
  4. 重量级锁:当轻量级锁升级为重量级锁时,会阻塞未能获取锁的线程,直到锁被释放。重量级锁通常会导致较高的线程切换成本,因此性能较低。

锁升级过程

  1. 偏向锁升级为轻量级锁:当另一个线程尝试访问已被偏向锁锁定的同步块时,偏向锁会升级为轻量级锁。此时,会通过CAS操作尝试获取锁。
  2. 轻量级锁升级为重量级锁:如果轻量级锁自旋等待超过一定次数或时间仍未获取到锁,那么会升级为重量级锁,阻塞未能获取锁的线程。

轻量锁和偏向锁的关系

轻量锁不能变成偏向锁。一旦轻量锁被使用,它就不会退回到偏向锁状态。这是因为轻量锁已经涉及到多个线程的竞争,而偏向锁只针对单一线程,所以它们之间没有直接的转换关系。

偏向锁和无锁的关系

偏向锁可以升级为无锁。在某些情况下,如果同步块内的代码执行速度非常快,且没有竞争,那么偏向锁可以在不实际锁定的情况下执行同步块,从而实现无锁状态。但是,这并不是一种直接的转换,而是偏向锁的一种优化行为。

总的来说,Java中的锁机制是一个复杂的系统,涉及到多种锁状态和转换关系。理解这些概念和过程对于优化并发性能和避免死锁等问题非常重要。