Java 锁机制

当没有竞争的时候,系统会默认使用偏斜锁。JVM 利用CAS(compare and swap)在 对象头的第一部分(mark word)设置 偏向线程ID,表示对象偏向于这个线程。 因为大部分并发场景下面 对象 生命周期 中最多被一个线程锁定, 使用偏斜锁的话可以降低 低竞争状态下的 额外开销。

这个时候如果有另外的线程试图锁定已经被倾斜过的对象,JVM会撤销(revoke)偏斜锁, 并切换到轻量级锁。 这时候轻量级锁 会根据 CAS 操作 Mark word 来试图 获取锁,如果成功就 切换为轻量级锁;否则 进一步 升级 为重量级锁。

 

自旋锁: 是竞争失败的线程,并不会真实的在操作系统层面挂起等待,而是JVM会让线程做几次空循环(For (;;)),循环几轮后,如果可以获得锁,那么进入临界区,如果还是不能获得锁的话,这时候才会在操作系统挂起等待。 一般在 低竞争并且占用锁的时间短的线程很实用。是一种在悲观锁中的乐观优化(因为JVM的synchronized是一种悲观锁 )。

 

死锁: 因为悲观锁独占CPU的特性,死锁就是线程A在持有锁A的情况下,试图进入锁B; 而线程B 在持有 锁B的情况下,试图进入锁A。如下图:

Java 锁机制_第1张图片

例如多个嵌套的 synchronized 有可能会发生死锁的情况。 所以为了避免死锁, 我们就需要 注意锁的获取顺序。 或者使用Object.wait() 或者  CountDownLatch.await()等带超时的方法。在长时间没有锁的情况下,即退出逻辑。

另外如果发生死锁的情况下可以使用jstack等工具去获取死锁发生的位置,这里就不过多阐述。

你可能感兴趣的:(Java 锁机制)