前言
- 在高并发领域,ReentrantLock有着广泛的用处,防止多线程带来的并发问题
- 对于源码,很多人和我一开始一样都觉得非常神秘
- 这次我将对ReentrantLock进行全方面的揭秘
核心
- AbstractQueuedSynchronizer
- AQS是JDK实现的CAS同步器。里面的核心是state和两个node
- state标识同步器现在的状态,node作为队列串联同步器中的节点
- 使用volatile保证参数的可见性
volatile Node prev;
volatile Node next;
private volatile int state;
整体结构
- ReentrantLock 调用内部类Sync,Sync继承AbstractQueuedSynchronizer
整体流程
- ReentrantLock调用内部类Sync的acquire方法,底层走的是AbstractQueuedSynchronizer,AbstractQueuedSynchronizer会尝试获取锁,获取失败之后会加入队列中,然后节点自旋去获取锁,一旦成功就将自己的节点至于头部,然后退出。
- cas实现(compareAndSet)。jdk9之前使用的是unsafe,jsk9之后使用的是varHandler。
核心代码
AQS:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
- tryAcquire是第一次尝试获取所,公平锁和非公平锁的区别只是判断自己节点是否除了head节点外还是在自己前面的,校验的是公平锁,不校验的是非公平锁
- addWaiter是节点加入到队列中
- acquireQueued里面执行的就是自旋操作
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);
}
}
释放锁
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;
}