可重入锁(ReentrantLock)源码分析

扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,阅读更多Spring源码分析Java并发编程文章。

微信公众号

问题

在阅读本文之前可以先思考一下以下两个问题

  • 1. ReentrantLock是如何在Java层面(非JVM层面)实现锁的?
  • 2. 什么是公平锁?什么是非公平锁?

简介

  • Lock是JUC包下的一个接口,里面定义了获取锁、释放锁等和锁相关的方法,ReentrantLock是Lock接口的一个具体实现类,它的功能是可重入地独占式地获取锁。这里有两个概念,可重入独占式。可重入表示的是同一个线程能多次获取到锁。独占式表示的是,同一时刻只能有一个线程获取到锁。
  • ReentrantLock实现的锁又可以分为两类,分别是公平锁非公平锁,分别由ReentrantLock类中的两个内部类FairSyncNonfairSync来实现。FiarSync和NonfairSync均继承了Sync类,而Sync类又继承了AbstractQueuedSynchronizer(AQS)类,所以ReentrantLock最终是依靠AQS来实现锁的。关于AQS的知识可以参考以下两篇文章。
  • 队列同步器(AQS)的设计原理
  • 队列同步器(AQS)源码分析
  • ReentrantLock有两个构造方法,一个无参构造方法,一个有参构造方法。通过无参构造方法创建对象时,创建的是非公平锁;有参构造方法中,可以传入一个boolean类型的变量,如果传入的是true,那么创建的是公平锁,如果传入的是false,那么创建的是非公平锁。
/**
 * Creates an instance of {@code ReentrantLock}.
 * This is equivalent to using {@code ReentrantLock(false)}.
 */
public ReentrantLock() {
   
    sync = new NonfairSync();
}

/**
 * Creates an instance of {@code ReentrantLock} with the
 * given fairness policy.
 *
 * @param fair {@code true} if this lock should use a fair ordering policy
 */
public ReentrantLock(boolean fair) {
   
    sync = fair ? new FairSync() : new NonfairSync();
}

公平锁

  • 当向ReentrantLock的构造方法中传入true时,创建的是公平锁。公平锁的lock()unlock()方法实现是由FairSync类中的lock()release()方法实现的(其中release()方法定义在AQS中)。
public static void main(String[] args) {
   
    ReentrantLock lock = new ReentrantLock(true);
    try{
   
        lock.lock();
        System.out.println("Hello World");
    }finally {
   
        lock.unlock();
    }
}
获取锁
  • 当调用lock.lock()时,会调用到FairSync.lock()方法,FairSync.lock()方法会调用AQS中的acquire()方法。
static final class FairSync extends Sync {
   
    final void lock() {
   
        // 调用acquire()获取同步状态
        acquire(1);
    }
}
  • 在AQS的acquire()方法中会先调用子类的tryAcquire()方法,此时由于我们创建的是公平锁,所以会调用FairSync类中的tryAcquire()方法。(关于acquire()方法的详细介绍,可以参考:队列同步器(AQS)源码分析)。

  • tryAcquire()方法的作用就是获取同步状态(也就是获取锁),如果当前线程成功获取到锁,那么就会将AQS中的同步状态state加1,然后返回true,如果没有获取到锁,将会返回false。FairSync类上tryAcquire()方法的源码如下。

protected final boolean tryAcquire(int acquires) {
   
        final Thread current = Thread.currentThread();
        
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
公平是一种多线程同步机制,它可以保证多个线程按照请求的顺序依次获得。在Java中,公平的实现类是ReentrantLock,下面我们来分析一下它的源码。 ReentrantLock的构造函数如下: ``` public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } ``` 可以看到,ReentrantLock的构造函数接受一个boolean类型的参数fair,用来指定该是否为公平。如果fair为true,则创建一个FairSync对象,否则创建一个NonfairSync对象。这两个对象都是ReentrantLock的内部类,它们分别实现了公平公平的逻辑。 FairSync的实现如下: ``` static final class FairSync extends Sync { final void lock() { acquire(1); } protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } } ``` FairSync继承了Sync类,它实现了公平的逻辑。FairSync中的lock方法直接调用了acquire方法,acquire方法中会调用tryAcquire方法来尝试获取。tryAcquire方法首先判断当前的状态,如果状态为0,表示没有被占用,这时它会判断是否有等待队列中的线程,如果没有,则尝试获取。如果状态不为0,表示已经被占用,这时它会判断当前线程是否为的持有者,如果是,则直接增加的状态计数器,否则返回false表示获取失败。 NonfairSync的实现如下: ``` static final class NonfairSync extends Sync { final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } } ``` NonfairSync同样继承了Sync类,它实现了公平的逻辑。NonfairSync中的lock方法首先尝试使用CAS操作来获取,如果成功则设置当前线程为的持有者,否则调用acquire方法。tryAcquire方法中调用了nonfairTryAcquire方法来尝试获取,这个方法与FairSync中的tryAcquire方法类似,只是它不会判断等待队列中的线程是否比当前线程更早请求。 总结一下,ReentrantLock实现了公平公平两种逻辑,它的内部类Sync、FairSync和NonfairSync分别实现了的基本逻辑,包括获取、释放等。在使用ReentrantLock时,我们可以选择使用公平公平,具体取决于我们的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值