1. 无锁状态
- 对象在没有被任何线程锁定时处于无锁状态。此时对象头中的锁标志位通常表示为无锁(例如,标记字段的特定位组合表示无锁或偏向锁状态)。
2. 偏向锁(Biased Locking)
- 初次获取:当线程首次获得对象锁时,如果对象处于无锁状态,系统会将其升级为偏向锁。此时会在对象头的 MarkWord 中记录当前线程的 ID,表明该锁偏向于这个线程。后续该线程再次请求该锁时,只需验证 MarkWord 中的线程 ID 是否与当前线程 ID 相符,相符则无需进一步同步操作即可直接获取锁。
- 撤销与偏向撤销:当有第二个线程尝试获取该偏向锁时,偏向锁将被撤销,恢复到无锁状态。随后,锁会根据竞争情况升级为轻量级锁或重量级锁。此外,为了应对程序运行过程中线程生命周期较短、偏向锁失效的情况,JVM 还会定期或在特定条件下进行全局偏向锁撤销操作。
3. 轻量级锁(Lightweight Locking)
- 获取:当线程 A 在偏向锁撤销后尝试获取锁时,如果发现锁已被偏向线程 B 持有,线程 A 将尝试使用 CAS(Compare-and-Swap)操作将对象头的 MarkWord 替换为指向线程 A 线程栈中锁记录(Lock Record)的指针,并将锁记录中的指针回写到 MarkWord。如果 CAS 成功,线程 A 获得锁,否则说明有其他线程(可能是线程 B 或其他新竞争者)也在尝试获取锁,此时进入下一步。
- 自旋与升级:若 CAS 失败,线程 A 会进入自旋状态,循环尝试获取锁。如果在一定次数(默认通常是10次)的自旋后仍未能获得锁,轻量级锁将升级为重量级锁。升级过程包括:线程 A 首先暂停自旋,然后在对象头中设置标志,触发锁膨胀,将锁变为重量级锁。同时,线程 A 会被挂起,加入到锁对象对应的 Monitor(重量级锁)的等待队列中。
4. 重量级锁(Heavyweight Locking)
- 获取:一旦锁升级为重量级锁,所有后续尝试获取锁的线程都会被阻塞,放入操作系统层面的等待队列中,由操作系统进行线程调度和上下文切换。
- 释放:持有锁的线程执行完同步代码块后,释放锁。操作系统会唤醒等待队列中的一个(或多个,取决于锁策略)线程,使其重新尝试获取锁。