偏向锁的两次竞争
使用 synchronized() 时,括号中的对象就是我们所谓的 锁
其实真正的 锁 的信息,存在与括号中对象的对象头中
对象头的组成:
内容 | 说明 |
---|---|
Mark Word | 存储对象的 Hashcode、锁信息、分代年龄 |
Class Metadata Address | 存储对象类型数据的指针 |
Array length | 数组的长度(如果对象是数组的话) |
主要看 MarkWord,它存放了锁信息,我们简化一下 MarkWord 存放的数据,仅拿出我们需要的:线程ID、偏向锁标志
偏向锁标志只有两个值:0和1,它用来表示当前是不是偏向锁
线程如何判断自己是否拿到偏向锁
线程读取一下锁对象头的 MarkWord 里的 线程ID 是不是自己的线程ID,如果是就是拿到了,不是就没拿到
两次竞争偏向锁
如果线程想竞争偏向锁,他会先向上面一样判断自己有没有拿到偏向锁,如果没有就会开始竞争偏向锁
第一次竞争
线程会先读取偏向锁标记,如果是 0,就会用 CAS 尝试将 0 变成 1,所以 偏向锁标记 的值可以表示:是否有线程在第一次竞争中胜利了
但其实这一步谁胜利了无所谓,关键在于第二次竞争
为什么要有第一次竞争
第一次竞争谁赢都无所谓,目的主要是为了:让 偏向锁标记 变为 1,也就是说,是为了把这个普通的对象,标记成一个偏向锁对象,所以其实第一次竞争我认为不能称之为竞争
第二次竞争
当线程读取偏向锁标记为 1 时,就会使用 CAS 来竞争,尝试将锁对象头中 MarkWord 存放的 线程ID 指向自己的线程。哪个成功指向自己,哪个线程就获得了偏向锁