我们今天主要讨论下这两个内部类,从而探讨下代码级别是如何实现公平锁和非公平锁的。
先看ReentrantLock加锁方法,可以自己去看源码,底层是在FairSync和NonfairSync这两个内部里面做的逻辑
static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }
static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); } /** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */ 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; } }
不同的是,非公平锁在lock时,先调用底层的unsafe原生类的CAS方法,获取当前锁的机会,如果获取不成功则和公平锁一样调用acquire(1);
我们再来看acquire(1)方法,在AQS中实现如下:
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
会先执行tryAcquire方法,然后根据短路与看时候需要进行acquireQueued,acquireQueued方法是指当前线程未获得锁的情况下,将该线程加入等待的引用链中
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; }
贴上公平锁的tryAcquire方法实现
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { 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; }
贴上非公平锁的tryAcquire方法实现
比较关键的差别是在hasQueuedPredecessors方法上,非公平锁不会调用该方法,公平锁中该方法的意思是检测当前线程是否为acquireQueued方法往head之后添加引用,如果是则利用CAS方法获得当前reentrantLock。
其实公平锁和非公平锁最大的差别就是在获取锁时,是否会去找当前头结点之后维护的等待队列。