文章仅用来自己整理、记录,不成体系,无法阅读!
ReentrantLock类图
ReentrantLock 主要就是通过实现 AQS 达到锁的效果,可以实现和synchronized一样的效果,并且具有扩展功能。如超时,支持公平锁。
构造函数
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
// 可以通过参数控制开启公平锁,默认非公平锁
// 公平锁会导致吞吐下降
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
获取锁
/**
* Acquires the lock.
*
* <p>Acquires the lock if it is not held by another thread and returns
* immediately, setting the lock hold count to one.
* 如果当前锁未被其他线程获取,则当前线程获取锁立即返回,设置计数器为1
*
* <p>If the current thread already holds the lock then the hold
* count is incremented by one and the method returns immediately.
* 重入:如果当前线程已经获取到该锁,则计数器加1立即返回
*
* <p>If the lock is held by another thread then the
* current thread becomes disabled for thread scheduling
* purposes and lies dormant until the lock has been acquired,
* at which time the lock hold count is set to one.
* 如果当前锁被其他线程获取,则当前线程将被阻塞,直到获取到锁,设置计数器为1
*/
public void lock() {
// 内部调用AQS设置状态为1
sync.acquire(1);
}
AQS acquire()
/**
* Acquires in exclusive mode, ignoring interrupts. Implemented
* by invoking at least once {@link #tryAcquire},
* returning on success. Otherwise the thread is queued, possibly
* repeatedly blocking and unblocking, invoking {@link
* #tryAcquire} until success. This method can be used
* to implement method {@link Lock#lock}.
*
* @param arg the acquire argument. This value is conveyed to
* {@link #tryAcquire} but is otherwise uninterpreted and
* can represent anything you like.
*/
public final void acquire(int arg) {
// 尝试获取锁不成功
if (!tryAcquire(arg) &&
// 入队
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// 此处仅在当前线程有被中断才会执行到这里,再次中断
selfInterrupt();
}
ReentrantLock.Sync tryAcquire()
// 非公平同步器调用nonfairTryAcquire
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
@ReservedStackAccess
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;
}
AQS addWaiter
/**
* Creates and enqueues node for current thread and given mode.
*
* @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
* @return the new node
*/
// 将当前 node 插入到队尾
private Node addWaiter(Node mode) {
Node node = new Node(mode);
for (;;) {
// 找到尾节点
Node oldTail = tail;
if (oldTail != null) {
// 设置关联 node.prev = oldTail
node.setPrevRelaxed(oldTail);
// cas 修改尾节点
if (compareAndSetTail(oldTail, node)) {
oldTail.next = node;
return node;
}
} else {
// 初始化头尾节点
initializeSyncQueue();
}
}
}
/**
* Initializes head and tail fields on first contention.
*/
private final void initializeSyncQueue() {
Node h;
// 头和尾设置同一个节点
if (HEAD.compareAndSet(this, null, (h = new Node())))
// TODO 这里为什么不使用 CAS
// 调用该方法一定是 tail == null
// 假如第一个线程设置头成功后没有设置尾节点
// 此时第二个线程仍然走到该方法,并且 CAS 头节点失败
// 因此,该逻辑一定是线程安全的
tail = h;
}
AQS 入队操作
/*
* Various flavors of acquire, varying in exclusive/shared and
* control modes. Each is mostly the same, but annoyingly
* different. Only a little bit of factoring is possible due to
* interactions of exception mechanics (including ensuring that we
* cancel if tryAcquire throws exception) and other control, at
* least not without hurting performance too much.
*/
/**
* Acquires in exclusive uninterruptible mode for thread already in
* queue. Used by condition wait methods as well as acquire.
*
* @param node the node
* @param arg the acquire argument
* @return {@code true} if interrupted while waiting
*/
final boolean acquireQueued(final Node node, int arg) {
boolean interrupted = false;
try {
for (;;) {
// 获取前一个节点
final Node p = node.predecessor();
// 如果是第一个节点 再次尝试获取锁
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return interrupted;
}
// 是否需要挂起
if (shouldParkAfterFailedAcquire(p, node))
// 挂起并清除中断状态
interrupted |= parkAndCheckInterrupt();
}
} catch (Throwable t) {
cancelAcquire(node);
if (interrupted)
selfInterrupt();
throw t;
}
}
/**
* Checks and updates status for a node that failed to acquire.
* Returns true if thread should block. This is the main signal
* control in all acquire loops. Requires that pred == node.prev.
*
* @param pred node's predecessor holding status
* @param node the node
* @return {@code true} if thread should block
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
// 前节点状态是 SIGNAL,park
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
// 前一个节点被取消
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
// 向前继续寻找,直到直到未取消的节点
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// ws <= 0
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
// 前节点设置为通知状态
// 死循环调用,第一遍设置为通知状态,下次进入会挂起
pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
}
return false;
}
加锁流程
如果当前锁未被其他线程获取,尝试获取锁
如果获取锁的线程是当前线程,锁状态字段值加1
如果获取锁不成功,入等待队列,并且不间断尝试,或者执行挂起操作
tryLock
直接调用nonfairTryAcquire
,不执行入队列操作,无论是否成功获取锁,直接返回。
所以,公平锁无法执行tryLock
有时间限制的获取锁流程和lock
流程基本一致
区别:
- 获取锁不成功需要判断是否达到超时时间
- 挂起操作需要设置超时时间
tryLock(long timeout, TimeUnit unit)
tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout)
/**
* Acquires in exclusive timed mode.
*
* @param arg the acquire argument
* @param nanosTimeout max wait time
* @return {@code true} if acquired
*/
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return true;
}
nanosTimeout = deadline - System.nanoTime();
// 超时返回
if (nanosTimeout <= 0L) {
cancelAcquire(node);
return false;
}
// 是否挂起 1.前置节点是通知状态 2.等待时间小于自旋时间
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} catch (Throwable t) {
cancelAcquire(node);
throw t;
}
}
解锁操作
调用 AQS release方法
/**
* Releases in exclusive mode. Implemented by unblocking one or
* more threads if {@link #tryRelease} returns true.
* This method can be used to implement method {@link Lock#unlock}.
*
* @param arg the release argument. This value is conveyed to
* {@link #tryRelease} but is otherwise uninterpreted and
* can represent anything you like.
* @return the value returned from {@link #tryRelease}
*/
public final boolean release(int arg) {
// 只有完全释放锁的时候才返回 true
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
// 唤醒后继节点
unparkSuccessor(h);
return true;
}
return false;
}
/**
* Wakes up node's successor, if one exists.
*
* @param node the node
*/
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
node.compareAndSetWaitStatus(ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
// 清除掉取消的节点
s = null;
// TODO 为什么从尾节点开始遍历?
// 盲猜:
// 正常情况,找到后继节点唤醒
// 如果后继节点是取消状态
// 如果从前向后查找,可能会出现其他线程将当前节点 next 断开的情况,无法找到后继需要唤醒的节点
// 如果从后向前查找,prev 指向不会断开,可以保证需要唤醒的节点正常唤醒
for (Node p = tail; p != node && p != null; p = p.prev)
if (p.waitStatus <= 0)
s = p;
}
if (s != null)
LockSupport.unpark(s.thread);
}
取消操作
/**
* Cancels an ongoing attempt to acquire.
*
* @param node the node
*/
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
if (node == null)
return;
node.thread = null;
// Skip cancelled predecessors
// 跳过前边的已经取消的节点
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// predNext is the apparent node to unsplice. CASes below will
// fail if not, in which case, we lost race vs another cancel
// or signal, so no further action is necessary, although with
// a possibility that a cancelled node may transiently remain
// reachable.
Node predNext = pred.next;
// Can use unconditional write instead of CAS here.
// After this atomic step, other Nodes can skip past us.
// Before, we are free of interference from other threads.
node.waitStatus = Node.CANCELLED;
// If we are the tail, remove ourselves.
// 如果 node 是尾节点,移除 node,替换 tail 为 pred
// pred next 设置为 null,后边的节点都是被取消的节点
if (node == tail && compareAndSetTail(node, pred)) {
pred.compareAndSetNext(predNext, null);
} else {
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
int ws;
// pred 不是 head
// pred 是通知状态或者 未被取消且设置通知状态并且线程不为空
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
pred.thread != null) {
// 设置 pred.next = node.next
Node next = node.next;
// TODO 如果 next.waitStatus > 0?
//
if (next != null && next.waitStatus <= 0)
pred.compareAndSetNext(predNext, next);
} else {
unparkSuccessor(node);
}
node.next = node; // help GC
}
}