图解 Java 中的可重入锁与非可重入锁

写锁呢就不可避免的要说可重入锁与不可重入锁。不可重入锁也有人成为非可重入锁,都是一个意思,不同的叫法而已!

前面我有篇文章《synchronized 是可重入锁吗?为什么?》写过 synchronized,今天我们再来借助 synchronized 来说可重入锁与不可重入锁。

可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提锁对象得是同一个对象或者 class),不会因为之前已经获取过还没释放而阻塞。Java 中 ReentrantLock 和 synchronized 都是可重入锁,可重入锁的一个优点是可一定程度避免死锁。

还是以 synchronized 为例,看下面的代码:

public class Xttblog {
    public synchronized void doSomething() {
        System.out.println("方法1执行...");
        doOthers();
    }
    // www.xttblog.com
    public synchronized void doOthers() {
        System.out.println("方法2执行...");
    }
}

在上面的代码中,类中的两个方法都是被内置锁 synchronized 修饰的,doSomething() 方法中调用 doOthers() 方法。因为内置锁是可重入的,所以同一个线程在调用 doOthers() 时可以直接获得当前对象的锁,进入 doOthers() 进行操作。

如果是一个不可重入锁,那么当前线程在调用 doOthers() 之前需要将执行 doSomething() 时获取当前对象的锁释放掉,实际上该对象锁已被当前线程所持有,且无法释放。所以此时会出现死锁。因此,我在前面那篇文章也说过,synchronized 是可重入锁!

那么 synchronized 是怎么实现可重入的呢?或者说可重入锁为什么就可以在嵌套调用时可以自动获得锁呢?我们还是看图说话!

还是打水的例子,有多个人在排队打水,此时管理员允许锁和同一个人的多个水桶绑定。这个人用多个水桶打水时,第一个水桶和锁绑定并打完水之后,第二个水桶也可以直接和锁绑定并开始打水,所有的水桶都打完水之后打水人才会将锁还给管理员。这个人的所有打水流程都能够成功执行,后续等待的人也能够打到水。这就是可重入锁。

图解 synchronized 可重入锁

但如果是非可重入锁的话,此时管理员只允许锁和同一个人的一个水桶绑定。第一个水桶和锁绑定打完水之后并不会释放锁,导致第二个水桶不能和锁绑定也无法打水。当前线程出现死锁,整个等待队列中的所有线程都无法被唤醒。

图解不可重入锁导致的死锁

之前我们说过 ReentrantLock 和 synchronized 都是重入锁,那么我们通过重入锁 ReentrantLock 以及非可重入锁 NonReentrantLock 的源码来对比分析一下为什么非可重入锁在重复调用同步资源时会出现死锁。

首先 ReentrantLock 和 NonReentrantLock 都继承父类AQS,其父类AQS中维护了一个同步状态 status 来计数重入次数,status 初始值为 0。

当线程尝试获取锁时,可重入锁先尝试获取并更新 status 值,如果 status == 0 表示没有其他线程在执行同步代码,则把 status 置为 1,当前线程开始执行。如果 status != 0,则判断当前线程是否是获取到这个锁的线程,如果是的话执行 status+1,且当前线程可以再次获取锁。而非可重入锁是直接去获取并尝试更新当前 status 的值,如果status != 0 的话会导致其获取锁失败,当前线程阻塞。

释放锁时,可重入锁同样先获取当前 status 的值,在当前线程是持有锁的线程的前提下。如果 status-1 == 0,则表示当前线程所有重复获取锁的操作都已经执行完毕,然后该线程才会真正释放锁。而非可重入锁则是在确定当前线程是持有锁的线程之后,直接将 status 置为 0,将锁释放。

可重入锁与不可重入锁的实现逻辑

可重入锁的持用场景非常的多,我就不列举了。反观非可重入锁的使用场景,网上基本上没有人列举。百度谷歌很久都没啥用,但是一般在分布式系统中的分布式锁,可以算是一个不可重入锁的使用场景吧!

图解 Java 中的可重入锁与非可重入锁

: » 图解 Java 中的可重入锁与非可重入锁

原创文章,作者:Carrie001128,如若转载,请注明出处:https://blog.ytso.com/251932.html

(0)
上一篇 2022年5月3日
下一篇 2022年5月3日

相关推荐

发表回复

登录后才能评论