ReentrantLock (重入锁)是 synchronized 的一个补充。用法就不用说了。
看看它的源码:
public ReentrantLock(boolean fair) {
// 确定是否使用公平锁。
sync = fair ? new FairSync() : new NonfairSync();
}
FairSync 公平 NonfairSync 非公平。都是内部类 都继承Sync,Sync继承AbstractQueuedSynchronizer。公平就是按序排队,非公平就是可抢占。
以公平锁为例:
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
// 获取锁
// 调用AbstractQueuedSynchronizer.accquire,accquire又会调用tryAcquire来获取锁。
// 见下面分析
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
* 重写AbstractQueuedSynchronizer的tryAcquire方法。
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); // 引用计数
if (c == 0) {
if (!hasQueuedPredecessors() && // 队列中是否有需要处理的线程。(hasQueuedPredecessors当队列为空 或 队列头为当前线程时 return false)
compareAndSetState(0, acquires)) { // 以乐观锁方式,设置state
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;
}
}
AbstractQueuedSynchronizer
public final void acquire(int arg) {
// 如果tryAcquire成功则直接返回,否则就添加一个排他锁到等待队列
// 然后判断当前是不是队列头,如是则调用tryAcquire获取,否则就监视前一个节点
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt();
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) { //如果是队列头,则执行获取动作
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) && //监视前一个节点是不是获得锁节点,并去掉中间取消的节点
parkAndCheckInterrupt()) // 暂停当前线程,等待中断
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node); // 取消
}
}
总结:在整个锁的处理中有几个点。
1,AbstractQueuedSynchronizer(队列同步器)
2,CAS (compareAndSet 乐观锁的实现)
3,UNSAFE.park 与 unsafe.unpark (线程的休眠与唤醒)