上一篇分享了AQS的基本原理:AQS(AbstractQueuedSynchronizer),在此基础上,再来看看ReentrantLock对AQS是怎么实现的,尤为是对可重入以及公平和非公平的理解java
先看看lock()方法:ui
final void lock() { acquire(1); }
/** *对AQS中对应方法的重写,位于FairSync类中,锁公平获取实现方式 */ protected final boolean tryAcquire(int acquires) {//acquires=1 final Thread current = Thread.currentThread();//获取当前线程 int c = getState();//获取AQS中state的值,0表示资源未被占用,既没有线程获取到锁 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; }
大概流程:线程
主要再来看一下hasQueuedPredecessors():code
/** *判断队列里面有没有比当前线程等待更久更先到等待队列的线程,越靠近head越优先获取锁即先到先得(公平性) */ public final boolean hasQueuedPredecessors() { Node t = tail; Node h = head;//当前已经得到锁的线程节点 Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); }
先来看看lock()方法:htm
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
和公平方式不一样的是,他会先尝试把state设置成1,若是设置成功,那就把持有锁的线程设置为本身,不然才去正常获取锁。
再看他对tryAcquire的重写:blog
protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }
/** *非公平方式获取锁 */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { //该步骤相似于上面lock()方法的第一步 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
public void unlock() { sync.release(1); }
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }