节点状态
/** 节点已被取消 */
static final int CANCELLED = 1;
/**
* 后继节点的线程处于等待状态,
* 而当前节点的线程如果释放了同步状态或者被取消,
* 那么就会通知后继节点,让后继节点的线程能够运行
*/
static final int SIGNAL = -1;
/**
* 节点在等待队列中,节点线程等待在Condition上,
* 不过当其他的线程对Condition调用了signal()方法后,
* 该节点就会从等待队列转移到同步队列中,然后开始尝试对同步状态的获取
*/
static final int CONDITION = -2;
/**
* 表示下一次的共享式同步状态获取将会无条件的被传播下去
*/
static final int PROPAGATE = -3;
参考资料
lock
方法流程
通过流程可以看出,公平与非公平只针对新线程与同步队列中的线程。
源码:
- 公平锁
final void lock() {
// 调用父类的 acquire
acquire(1);
}
// 父类
public final void acquire(int arg) {
// 尝试抢锁
if (!tryAcquire(arg) &&
// 抢锁失败加入队列排队获取锁,此步骤为自旋阻塞,addWaiter对应流程图2
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// 如果在队列中抢锁失败,则关闭当前线程
selfInterrupt();
}
// 尝试抢锁
protected final boolean tryAcquire(int acquires) {
// 获取当前线程
final Thread current = Thread.currentThread();
// 获取当前 state 值
int c = getState();
// 如果当前 state 为没人占用状态
if (c == 0) {
// 同步队列中是否有抢锁的线程,对应流程图1
if (!hasQueuedPredecessors() &&
// 如果前面没有抢锁的线程,CAS 改写 state
compareAndSetState(0, acquires)) {
// 如果写成功则将当前锁的持有人标记为当前线程
setExclusiveOwnerThread(current);
return true;
}
}
// 当前 state 为当前线程占用
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
- 非公平锁
final void lock() {
// CAS 改写 state,写成功代表抢锁成功
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
// 上面写失败了就调用父级的 acquire 方法,同公平锁
acquire(1);
}
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()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
- acquireQueued 队列阻塞抢锁
// 对应流程3
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 获取当前结点的上一个节点
final Node p = node.predecessor();
// 如果上一个节点为 head,则尝试获取锁
if (p == head && tryAcquire(arg)) {
// 抢锁成功后将 head 设为当前节点
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 抢锁失败,判断当前线程是否应该关闭
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
// 抢锁失败,进行取消操作
if (failed)
cancelAcquire(node);
}
}
wait & signal (等待与唤醒)
阻塞队列中,如果当前队列为空,则会调用notEmpty.await()
方法,notEmpty
为ConditionObject
,通常阻塞队列中会有两个ConditionObject
,一个负责【取(notEmpty)】的线程,一个负责【存(notFull)】的线程。一个ConditionObject
就是一个等待队列,调用await()
方法就是将当前线程从同步队列移到等待队列中。
源码解析:
public final void await() throws InterruptedException {
// 如果当前线程是中断状态则抛出中断异常
if (Thread.interrupted())
throw new InterruptedException();
// 将节点加入等待队列,对应流程1
Node node = addConditionWaiter();
// 释放当前节点所持的锁,对应流程2
int savedState = fullyRelease(node);
int interruptMode = 0;
// 如果当前节点不在同步队列中,则挂起等待唤醒,对应流程3
// 当线程被唤醒时,节点会加入同步队列,则会跳出 while,进入下面的逻辑
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 进入同步队列抢锁
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
- signal
public final void signal() {
// 如果不是当前持锁的线程操作,则抛出异常
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
// 如果等待队列有线程在等待
doSignal(first);
}
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
/*
* 如果不能修改状态,则表示当前节点已被取消
*/
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
// 将节点加入同步队列,返回当前节点的上一个节点
Node p = enq(node);
// 获取上一个节点的等待状态
int ws = p.waitStatus;
// 如果上一个节点为取消
// 或者上一个节点的状态已经时 SIGNAL 状态
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
// 唤醒当前节点
LockSupport.unpark(node.thread);
// 否则就交给同步队列进行唤醒,每个线程释放锁时都会去唤醒他的下一个节点
return true;
}
- realse
public final boolean release(int arg) {
// 尝试释放锁
if (tryRelease(arg)) {
Node h = head;
// 释放成功后唤醒下一个节点(如果有的话),对应流程4
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}