首页 > 代码库 > Java并发编程 ReentrantLock 源码分析

Java并发编程 ReentrantLock 源码分析

ReentrantLock 一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。 这个类主要基于AQS(AbstractOwnableSynchronizer)封装的 公平与非公平锁。

所谓公平锁就是指 在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程,换句话说也就是先被锁定的线程首先获得锁。 非公平锁正好相反,解锁时没有固定顺序。

 

让我们边分析源代码边学习如何使用该类

先来看一下构造参数,默认是非公平锁。

 1     /** 2      * Creates an instance of {@code ReentrantLock}. 3      * This is equivalent to using {@code ReentrantLock(false)}. 4      */ 5     public ReentrantLock() { 6         sync = new NonfairSync(); 7     } 8  9     /**10      * Creates an instance of {@code ReentrantLock} with the11      * given fairness policy.12      *13      * @param fair {@code true} if this lock should use a fair ordering policy14      */15     public ReentrantLock(boolean fair) {16         sync = fair ? new FairSync() : new NonfairSync();17     }

 

NonfairSync是非公平锁,我们先来看非公平锁,是一个内部类继承了Sync。

 1     /** 2      * Sync object for non-fair locks 3      */ 4     static final class NonfairSync extends Sync { 5         private static final long serialVersionUID = 7316153563782823691L; 6  7         /** 8          * Performs lock.  Try immediate barge, backing up to normal 9          * acquire on failure.10          */11         final void lock() {12             if (compareAndSetState(0, 1))13                 setExclusiveOwnerThread(Thread.currentThread());14             else15                 acquire(1);16         }17 18         protected final boolean tryAcquire(int acquires) {19             return nonfairTryAcquire(acquires);20         }21     }

我们看到它继承了Sync,我们接着看这个类的源码。

 1     abstract static class Sync extends AbstractQueuedSynchronizer { 2         private static final long serialVersionUID = -5179523762034025860L; 3  4         abstract void lock(); 5  6         final boolean nonfairTryAcquire(int acquires) { 7             final Thread current = Thread.currentThread(); 8             int c = getState(); 9             if (c == 0) {10                 if (compareAndSetState(0, acquires)) {11                     setExclusiveOwnerThread(current);12                     return true;13                 }14             }15             else if (current == getExclusiveOwnerThread()) {16                 int nextc = c + acquires;17                 if (nextc < 0) // overflow18                     throw new Error("Maximum lock count exceeded");19                 setState(nextc);20                 return true;21             }22             return false;23         }24 25         protected final boolean tryRelease(int releases) {26             int c = getState() - releases;27             if (Thread.currentThread() != getExclusiveOwnerThread())28                 throw new IllegalMonitorStateException();29             boolean free = false;30             if (c == 0) {31                 free = true;32                 setExclusiveOwnerThread(null);33             }34             setState(c);35             return free;36         }37     }

 

Sync这个类与AbstractQueuedSynchronizer 一起完成了锁的逻辑,现在我们开始从头分析一个线程如何获取锁,以及获取不到锁时如何被阻塞。当用户调用lock方法获取锁的时候,首先会先通过compareAndSetState(NonfairSync第11行)来设置锁定状态,如果原先状态为0,则说明目前没有线程持有锁,那么设置状态为1,并且设置当前线程是当前拥有独占访问的线程(setExclusiveOwnerThread),那么另外一种情况就是compareAndSetState方法返回false,也就是说之前已经有线程持有锁,那么就会执行acquire方法(NonfairSync第15行),这个方法是AbstractQueuedSynchronizer里面的方法。

    public final void acquire(int arg) {        if (!tryAcquire(arg) &&            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))            selfInterrupt();    }

首先调用了tryAcquire方法,这个类在子类当中实现,也就是上面NonfairSync第18行,实际上他调用了 nonfairTryAcquire,这个方法分两步,首先在判断一下状态(state)是否等于0,也就是重新尝试获取所,如果获取到锁则改变状态compareAndSetState 然后设置当前线程是当前拥有独占访问的线程(setExclusiveOwnerThread),跟上面讲到的一样。

如果重新尝试获取所失败,则判断是不是当前线程重复加锁,如果是的话就把状态进行增加。

如果上面都不是就返回FALSE, 如果返回FALSE 那么 acquire(int arg)方法的acquireQueued就会执行,这个方法会把不能获取锁的线程形成一个CHL队列保存起来,然后把线程阻塞。上面就基本讲完了

线程如何获取锁, 获取到锁就把状态设置成1。

如果是持有锁的线程继续调用 LOCK方法,那就把状态进行叠加。

如果获取不到锁,那么AbstractQueuedSynchronizer 会把线程以一个CHL队列的形式保存起来,然后设置线程,等待释放。