JUC全文
AQS
- JUC包的核心,
Abstract Queued Synchronizer,抽象队列同步器,底层是双向队列,ReentrantLock的底层 - AQS队列特点
- 队列中的第一个节点,是占有锁的线程对应的节点
- 初始化队列时,需要初始化两个节点
- CLH算法,自旋锁算法,充分运用CPU
- 六个步骤
- 抢锁
- 释放锁
- 入队
- 出队
- 阻塞
- 唤醒
waitStatus
0 默认
//取消
static final int CANCELLED = 1;
//闹钟,需要被唤醒,可挂起
static final int SIGNAL = -1;
// Condition时的状态
static final int CONDITION = -2;
// 共享模式下,countDownLatch下的标记状态
static final int PROPAGATE = -3;
抢锁
tryAcquire抢锁- 公平锁和非公平锁存在差异的地方,占有锁的线程已经执行完任务,释放了锁,将状态位恢复,这时恰好来了一个线程的时候,如果非公平锁没有争抢到,那么也像公平锁一样排队
- 非公平锁
- 看锁标志位
state,默认是0,没有线程占用锁,线程可以占有锁,改成1,需要一种机制(AQS),保证同一时刻,只能有一个线程能改state - 此时
state为0,那么可以抢锁 - 有线程占有锁,这时有线程来抢锁,需要判断
- 当前来抢锁的线程是否为占有锁的线程,如果是,则重入(双层锁),
state+1,释放时需要释放对应的次数- 当前来抢锁的线程不是占有锁的线程,抢锁失败
- 优化,看等待区域是否有其他线程,如果有,该锁已经被占用
hasQueuedPredecessors看等待区是否有其他线程等待(等待区域通过链表连接),如果没有,再试着调用compareAndSetState设置标志位hasQueuedPredecessors
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
// true的情况,说明有线程排队 head != tail 且 头节点后有线程,但是该线程不为当前线程
// (s = h.next) == null 是为了防止空指针,s == null 为真 就不会继续判断
// false的情况 head == tail(没有其他线程线程排队) 或 s.thread 为当前线程,当前线程已经排第二个了
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
- 没有其他线程等待,且设置成功,将当前线程进行设置
- 如果
state不为0,那么就是重入逻辑,检查当前线程是否为占有锁的线程
入队
- 没有抢到锁
tryAcquire返回false,那么尝试入队 addWaiter- 队列中有无节点,如果没有,需要
自旋初始化,进入enq方法,生成两个节点
private Node enq(final Node node) {
//第一次时进行了两次循环
//并且自旋放入
for (;;) {
//第一次tail为null
Node t = tail;
if (t == null) { // Must initialize
//生成一个空节点设置为head和tail
if (compareAndSetHead(new Node()))
tail = head;
} else {
//第二次循环,将新加入的node.prev指向head/tail
//非初始化时,新入队的节点,指向前一个节点,并将tail设置为新加入的节点,
//交换完后,此时t为前一个节点
node.prev = t;
//将tail设置为node
if (compareAndSetTail(t, node)) {
//此时t仅为head,将head.next设置为node
t.next = node;
return t;
}
}
}
}
- 如果有,尾部插入
private Node addWaiter(Node mode) {
//包装成node
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;
if (pred != null) {
node.prev = pred;
//将新node设置为tail
if (compareAndSetTail(pred, node)) {
//前一个node指向新node(也就是tail)
pred.next = node;
return node;
}
}
//如果直接插入失败,也需要自旋处理
enq(node);
return node;
}
- 入队完成后,尝试
自旋抢锁
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);
}
}
shouldParkAfterFailedAcquire
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL) //-1
return true;
if (ws > 0) { //前面的节点可以被取消
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else { //对于最开始来说,head.waitStatus为0,那么将其设置为-1,也就是上闹钟
//第二次进入时,则能返回true
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
释放锁
unlock- 解决
重入问题;锁状态位恢复为0;唤醒其他线程 tryRelease,改变state,当state==0时,返回true
protected final boolean tryRelease(int releases) {
int c = getState() - releases; //state - 1
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
唤醒
release,当tryRelease解决重入后,唤醒线程
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
// 要保证头节点为0,并唤醒后面的节点
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
unparkSuccessor
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
//某些信号量会导致waitStatus<0
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
//s == null 防止空指针,s是被取消的节点,找到非被取消的s节点唤醒
if (s == null || s.waitStatus > 0) {
s = null;
//从尾部开始
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
//找到node的下一个waitStatus<=0的睡眠节点
s = t;
}
if (s != null)
//唤醒
LockSupport.unpark(s.thread);
}
出队
- 由被唤醒的线程来做
- 当进入
parkAndCheckInterrupt阻塞后,被唤醒,将再次进入这个线程,尝试抢锁
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);
//将头节点的next设置为null,此时p节点没有被指向或者指向另一个node
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) //阻塞
interrupted = true;
}
} finally {
if (failed)
//当期间有异常发生,将该node.waitStatus置为Node.CANCELLED - 1
//将当前节点删除
cancelAcquire(node);
}
}
setHead
private void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
}
cancelAcquire处理唤醒失败,将该node.waitStatus置为Node.CANCELLED - 1,将当前节点删除,删除头节点会由下一个的节点删除
private void cancelAcquire(Node node) {
if (node == null)
return;
node.thread = null;
//找到当前节点的最前面没被取消的节点
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
//取当前父节点的下一个节点
Node predNext = pred.next;
//将当前节点设置为可取消的
node.waitStatus = Node.CANCELLED;
//当前节点为tail节点,直接将当前父节点设置为tail,因为prevNext是cancel
//如果node.prev 就是pred,那么也可以直接这么操作,此时predNext就是node
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
} else {
int ws;
//不是头节点 且 状态为-1,待唤醒 或 (ws < 0 且 设置为-1成功)
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
//将node的next,连接上pred,相当于从中间删除node
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
//如果是头节点 再次尝试唤醒node,因为已经没有别的节点了
unparkSuccessor(node);
}
//node指向自己,让gc回收
node.next = node; // help GC
}
}
Condition
- AQS的Node节点中有
nextWaiter属性,用于连接await()的等待节点
不带头节点的队列
await
- 创建节点插入等待队列
- 获取当前同步队列的状态,并释放锁
只有获得了lock的线程,才能进行await,否则会抛IllegalMonitorStateException
- 循环检测是否被加入同步队列,也就是苏醒,开始抢锁
响应中断
await()
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 包装成Node,尾插入等待队列
Node node = addConditionWaiter();
// 释放当前线程占用的lock,并唤醒下一个节点
int savedState = fullyRelease(node);
int interruptMode = 0;
// 当前是否被移动到AQS同步队列,因为await的主要目标就是挂起,直到被signal
// 最开始加入的是等待队列
while (!isOnSyncQueue(node)) {
// 挂起当前线程
LockSupport.park(this);
// 中断后,会跳出循环
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 自旋等待获取到lock
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
// 处理中断情况
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
addConditionWaiter()加入等待队列
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
// 包装成Node 设置状态为 Node.CONDITION
Node node = new Node(Thread.currentThread(), Node.CONDITION);
// 插入尾
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
// 更新尾队列
lastWaiter = node;
return node;
}
fullyRelease当前线程释放锁,说明如果不是上锁的lock,进行await,会抛异常
final int fullyRelease(Node node) {
boolean failed = true;
try {
// 此时应该是1
int savedState = getState();
// 释放资源
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
isOnSyncQueue判断是否移动到了同步队列
final boolean isOnSyncQueue(Node node) {
// 检查状态
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
// 如果状态是0,且是一个后继节点,那么肯定加入了同步队列,可以唤醒
if (node.next != null) // If has successor, it must be on queue
return true;
// 从同步队列尾部开始找,如果找到了就在
return findNodeFromTail(node);
}
awaitNanos在循环期间,对进行判断,超时后,设置节点为状态并break
signal
signal
public final void signal() {
// 检测当前线程是否获得lock
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
//唤醒等待队列中的第一个
doSignal(first);
}
doSignal唤醒操作
private void doSignal(Node first) {
do {
// firstWaiter 往后移动,并检查等待队列后面是否有节点
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
transferForSignal移动到同步队列,等待抢锁
final boolean transferForSignal(Node node) {
// 更新状态为0
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
// 加入同步队列
Node p = enq(node);
int ws = p.waitStatus;
// 唤醒当前线程,将该节点设置为可挂起-1
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
signalAll
public final void signalAll() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignalAll(first);
}
doSignalAll从第一个开始,移动全部的,加入同步队列,并唤醒
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null;
do {
Node next = first.nextWaiter;
first.nextWaiter = null;
transferForSignal(first);
first = next;
} while (first != null);
}