创建的时候,默认使用的是 非公平队列;公平和非公平的区别就是入队的时候。非公平是不管队列中是否存在排队的节点直接尝试枪锁,而公平的则是会首先判断队列中存不存在排队的节点。
获取锁
final void lock() {
// 非公平和公平的差异是 ,非公平上来会尝试获取锁
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else{
//获取锁失败后执行此方法
acquire(1);
}
}
执行 acquire获取锁方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// 1、tryAcquire 非公平的逻辑
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
// 非公平锁的执行逻辑
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()) {
//重入直接 将 state的值加即可
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
// 获取锁失败
return false;
}
//当获取锁失败后,会进入 入队操作
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
创建队列并加入到队列中 addWaiter
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) {
// 代表当前队列已经初始化了.此处设置当前的前置节点,如果下面的cas失败,后面的 enq方法依旧会再重新修改.
node.prev = pred;
// 因为存在多线程操作,所以使用CAS修改尾节点
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
// 如果队列没有初始化或者 设置尾节点失败后,下面这个方法保证入队
enq(node);
return node;
}
// 此方法通过自旋保证当前节点一定入队! 此方法返回的是之前的尾节点Node
private Node enq(final Node node) {
for (;;) {
// 得到当前的尾节点
Node t = tail;
if (t == null) { // Must initialize
// 没有则初始化,通过cas保证只有一个线程初始化成功
if (compareAndSetHead(new Node()))
tail = head;
} else {
// 设置当前的前置节点位尾节点
node.prev = t;
if (compareAndSetTail(t, node)) {
// 尝试设置尾节点,如果修改为尾节点成功之后,修改之前的尾节点的next为当前节点
t.next = node;
// 返回之前的尾节点
return t;
}
}
}
}
acquireQueued方法 在当前线程被park需要做几件事 :
如果当前节点的前驱节点为头节点,则再次尝试获取锁;
如果获取锁失败,需要修改当前节点的前驱节点为 Node.SIGNAL状态
park自己线程
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;
}
// 检查并移除队列中取消的节点,修改前驱节点的 waitStatus = Node.SIGNAL
if (shouldParkAfterFailedAcquire(p, node)
//阻塞当前线程
&& parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed){
//如果操作失败则将此节点移除队列
cancelAcquire(node);
}
}
}
shouldParkAfterFailedAcquire 修改前驱节点的状态, 如果前驱节点为Node.CANCEL则 修改前驱节点为 正常的节点
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.
*/
//如果当前前驱节点的状态 > 0 即为 Node.CANCELLED状态后需要移除节点
do {
//移除所有装状态为 Node.CANCELLED状态的节点
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.
*/
//修改当前前驱节点的状态为 -1
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
parkAndCheckInterrupt 阻塞当前线程
private final boolean parkAndCheckInterrupt() {
// 直接阻塞当前节点线程
LockSupport.park(this);
return Thread.interrupted();
}
unparkSuccessor 唤醒当前节点的下一个非Node.CANCEL节点
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)
//如果节点不为 null 唤醒正常的节点
LockSupport.unpark(s.thread);
}
cancelAcquire 取消当前节点如果当前节点是 头节点则唤醒后面的正常节点
/**
* 移除当前节点;
* 1、检查当前节点的前驱节点是否存在 Node.CANCEL状态的节点,存在则移除这些节点.
* 2、如果当前节点是尾节点,修改当前节点的前驱节点为尾节点
* 3、如果是头节点则唤醒后面的正常节点.
*/
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;
// 如果当前节点的后置节点是正常节点直接将节点的next设置为前驱节点的next
if (next != null && next.waitStatus <= 0) {
compareAndSetNext(pred, predNext, next);
}
} else {
// 如果是第一个节点的话,会执行唤醒下一个节点
unparkSuccessor(node);
}
node.next = node; // help GC
}
}