Java 锁机制

synchronized

在 jdk1.6 之后,synchronized 原语通过引入偏向锁、轻量锁进行了优化。

synchronized 是通过 monitor_entermonitor_exit 来控制的,通过 javap 反编译能观察到。

线程在进入 synchronized 代码块时,将通过获取对象头内 Mark Work 的锁标记来决定是否进入 临界区。

偏向锁

没有多线程竞争环境,如果没有设置 -XX:-UseBiasedLocking 关闭偏向锁的话将会通过 CAS 获取锁,并设置持有锁的线程 id,当该线程再次尝试获取锁时,如果锁内线程为当前线程则直接判断获取锁标记。

轻量锁

在多个线程尝试获取偏向锁时,当线程获取偏向锁失败时将会膨胀为轻量锁,通过CAS操作来获取锁标记进入临界区。

重量锁

如果轻量锁的 CAS 操作失败时,将会升级为重量级锁。

重量锁依赖底层的 Mutex Lock 总线锁,需要将用户态切换为内核态,成本较大。

重入锁

synchronized 偏向锁和 ReentrantLock 中都设计了重入锁,

自旋锁

当多线程环境下,线程获取锁标记或立马释放时,自旋锁就有其意义。

在 Java 源码的AbstractQueuedSynchronizer 中,线程的出现竞争时就是先是尝试进行自旋锁,之后再进行锁升级。

自旋锁消除了用户态切换至内核态的上下文切换,但是也增加cpu的消耗。

锁降级

在jvm进入安全点时,会检测空闲的 monitor 并对其进行锁降级以提高下次获取锁时的效率。