reentrantLock调用lock的fairSync版本
1 reentrantLock调用lock
public void lock() {
sync.lock(); -> 2 :调用sync的lock方法,选的fairsync作为例子
}
2 调用acquire方法,尝试获取锁
final void lock() {
acquire(1); -> 3
}
3 (1)获取锁成功,退出. (2)获取锁失败,添加node至AQS尾部.详细请看方法指示的标号
public final void acquire(int arg) {
if (!tryAcquire(arg) && -->4
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) ---->6(5)
selfInterrupt();
}
4 原子地获取锁,(1)如果锁未被占用,获取成功则将state由0添加至1.(2)如果锁被当前线程占用,重入则添加state计数器,(3)否则失败
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;
}
5 将代表当前线程的Node原子性地添加至队列尾部.(1).尾部不为空则cas操作尾部引用设置为当前node.并且将之前的尾部node与当前node相连. (2)尾部为空则设置头尾为一个新的Node,然后设置当前node为尾
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
6 如果node的前节点为head,如果获取锁权限成功,则将头节点设置为当前节点,并且释放前节点,返回interrupted状态(设置interupted用)
如果前节点不为head或者获取锁权限失败, 则根据前驱节点的waitStatus如果为signal则阻塞当前线程,如果不为signal则设置为signal继续循环
循环
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) && ---->7
parkAndCheckInterrupt()) ---->8
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node); -- 9
}
}
7 前驱节点为signl则直接返回true…
如果前驱节点为cancel,则直到前驱结点的前驱…状态不为取消的节点,然后将此节点的后继者设置为当前节点. return false
否则cas原子性地将前节点地status设置为signal return false
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
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 {
/*
* 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.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
8 locksupport 将当前线程的blocker设置为当前AQS .阻塞当前线程. 醒了就设置为空.传递interupted状态
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
private static void setBlocker(Thread t, Object arg) {
// Even though volatile, hotspot doesn't need a write barrier here.
UNSAFE.putObject(t, parkBlockerOffset, arg);
}
9 将node的waitStatus置为CANCELLED,将与之相连的已被取消的前结点全部移出AQS,然后将前结点的状态置为SIGNAL,并且将当前结点的后一个结点连接在之后(非cancel的情况下).如果失败了,那么就执行10
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.
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.
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, 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;
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
unparkSuccessor(node); -->10
}
node.next = node; // help GC
}
}
10.对于node后一个结点,如果waitstatus 为cancel或者为空,则从AQS尾部开始,找到第一个不为空的结点赋值给s变量.
最后唤醒s结点代表的线程.
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)
compareAndSetWaitStatus(node, 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;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}