偏向锁是jdk6及后续版本针对“虽有同步代码块,但是大部分时间是不存在锁竞争的”这一情形做的锁机制优化:只在开始时做一次CAS操作,将共享对象的对象头中Mark Word中记录的线程id记录为当前请求获取偏向锁的线程id,以后再也没有同步操作。
必知事实:
- 在jdk6、jdk7、jdk8默认开启;
- 可以通过可以通过-XX:-UseBiasedLocking来禁用,-XX:+UseBiasedLocking来开启。
偏向锁的执行路径
一个线程执行遇到同步代码块,假设 Jdk 默认开启了偏向锁这一优化功能:
(1)初始时共享对象处于偏向锁状态,并且 ThreadID 为0;
(2)当一个线程试图锁住一个处于偏向锁状态的共享对象时,通过一个 CAS 操作将自己的 ThreadID 放置到 Mark Word 中相应的位置,如果 CAS 操作成功进入第3步,否则进入第 4 步;
(3)线程执行到这里,表示当前没有锁竞争,共享对象继续保持偏向锁状态,但是这时ThreadID字段被设置成了偏向锁持有者的ID,然后进入到第(6)步
(4)当前线程执行 CAS 获取偏向锁失败,表示在该共享对象上存在锁竞争偏向锁被另一个线程持有,则需要撤销偏向锁状态:当到达全局安全点时,挂起持有偏向锁的线程,将共享对象的 Mark Word 中的线程id置为 0,释放被阻塞在安全点的当前线程,当前线程进入到轻量级锁的执行路径中,同时被撤销偏向锁的线程继续往下执行同步代码;
(5)当一个线程试图锁住一个处于偏向锁状态并且 ThreadID 不等于自己的ID时,这时由于存在锁竞争必须进入到第 4 步来撤销偏向锁。
(6)执行同步代码块