# 偏向锁

<mark style="color:blue;">**偏向锁**</mark>也是 JDK 6 中引入的一项锁优化措施，它<mark style="color:blue;">**的目的是消除数据在无竞争情况下的同步原语**</mark>，进一步提高程序的运行性能。

{% hint style="success" %}
<mark style="color:blue;">**如果说轻量级锁是在无竞争的情况下使用 CAS 操作去消除同步使用的互斥量，那偏向锁就是在无竞争的情况下把整个同步都消除掉，连 CAS 操作都不去做了。**</mark>
{% endhint %}

偏向锁中的“偏”，就是偏心的“偏”、偏袒的“偏”。它的意思是**这个锁会偏向于第一个获得它的线程，如果在接下来的执行过程中，该锁一直没有被其他的线程获取，则持有偏向锁的线程将永远不需要再进行同步。**

假设当前虚拟机启用了偏向锁，那么**当锁对象第一次被线程获取的时候，虚拟机将会把对象头中的标志位设置为“01”、把偏向模式设置为“1”，表示进入偏向模式。同时使用 CAS 操作把获取到这个锁的线程的 ID记录在对象的 Mark Word 之中。**&#x5982;果 CAS 操作成功，持有偏向锁的线程以后每次进入这个锁相关的同步块时，虚拟机都可以不再进行任何同步操作（例如加锁、解锁及对 Mark Word 的更新操作等）。

**一旦出现另外一个线程去尝试获取这个锁的情况，偏向模式就马上宣告结束。**&#x6839;据锁对象目前是否处于被锁定的状态决定是否撤销偏向（偏向模式设置为“0”），撤销后标志位恢复到未锁定（标志位为“01”）或轻量级锁定（标志位为“00”）的状态，后续的同步操作就按照轻量级锁的加锁过程去执行。

偏向锁、轻量级锁的状态转化及对象 Mark Word 的关系如图所示：

<figure><img src="https://2079151893-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpYHRX8DEEQK5j0XpL9Sz%2Fuploads%2FjNRKRxQJflZEWc06wuvr%2Fimage.png?alt=media&#x26;token=0b3cf7f6-f0d3-4bcb-be20-11d43f1942ed" alt=""><figcaption></figcaption></figure>

{% hint style="success" %}
**当对象进入偏向状态的时候，Mark Word 大部分的空间（23 个比特）都用于存储持有锁的线程 ID 了，这部分空间占用了原有存储对象哈希码的位置，那原来对象的哈希码怎么办呢？**

在 Java 语言里面一个对象如果计算过哈希码，就应该一直保持该值不变。作为绝大多数对象哈希码来源的 Object::hashCode() 方法，返回的是对象的一致性哈希码（Identity Hash Code），这个值是能强制保证不变的，它通过在对象头中存储计算结果来保证第一次计算之后，再次调用该方法取到的哈希码值永远不会再发生改变。

因此，**当一个对象已经计算过一致性哈希码后，它就再也无法进入偏向锁状态了**；而**当一个对象当前正处于偏向锁状态，又收到需要计算其一致性哈希码请求时，它的偏向状态会被立即撤销，并且锁会膨胀为重量级锁。**&#x5728;重量级锁的实现中，对象头指向了重量级锁的位置，代表重量级锁的 ObjectMonitor 类里有字段可以记录非加锁状态（标志位为“01”）下的 Mark Word，其中自然可以存储原来的哈希码。
{% endhint %}

{% hint style="warning" %}
**偏向锁可以提高带有同步但无竞争的程序性能**，但它同样是一个带有效益权衡（Trade Off）性质的优化，也就是说它并非总是对程序运行有利。**如果程序中大多数的锁都总是被多个不同的线程访问，那偏向模式就是多余的。**
{% endhint %}
