AbstractQueuedSynchronizer(AQS)
用于构建同步工具的框架
-
ReentrantLock、Semaphore、CountDownLatch、ReentrantReadWriteLock、SynchronousQueue、FutureTask是基于AQS实现 – 将功能委托给内部AQS子类
-
AQS提供原子式的同步状态管理 - 使用整数属性state表示资源状态,具体语义有同步器定义
- getState()
- setState()
-
compareAndSetState()
-
AQS提供获取与释放资源的操作,并维护一个线程的等待队列。AQS支持独占模式和共享共享两种方式访问资源,通常只在子类中实现一种模式
- acquire()、acquireInterruptibly() 通过调用子类实现的tryAcquire()进获取操作,tryAcquire()返回true时,表示获取成功;获取失败时,将线程阻塞,加入等待队列,直到tryAcquire()返回true
- acquireShared()、acquireInterruptibly() 类似acquire()
- release() 通过调用子类实现的tryRelease()释放; 在tryRelease返回true时,尝试取消一个或多个线程的阻塞
- releaseShared() 同上,调用子类的tryReleaseShared()
-
acquire()的基本操作:
while (!tryAcquire(arg)) { if(当前线程不在队列中) 将线程入队; 可能阻塞线程; } -
release()的基本操作:
if (tryRelease(arg)) unblock队首的线程; -
以AQS为基础实现同步器:使用使用getState(),setState(), compareAndSetState()重写tryAcquire(), tryAcquireShared(), tryRelease(), tryReleaseShared(), isHeldExclusively()。使用acquire(), acquireShared(),release(), releaseShared() 构建同步器。
ReentrantLock的实现
-
ReentrantLock下实现中不同的AQS: FairSync(用于公平锁), NonfairSync(用于非公平锁)
-
公平锁使用FairSync实现lock()
-
状态为0表示该锁未被持有,大于0表示该所被持有(加锁的次数)
-
tryAcquire的实现:
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { // !hasQueuedPredecessors(): 没有其他线程在队列中等待acquire // compareAndSetState(0, acquires): 安全地改变状态 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); //设置独占线程 return true; } } else if (current == getExclusiveOwnerThread()) { // 如果该sync已经被该线程独占了,不会有其他线程竞争,可以安全的增加重入的数量 int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
-
-
非公平锁使用NonfairSync实现lock()
-
状态为0表示该锁未被持有,大于0表示该所被持有(加锁的次数)
-
先调用lock() 尝试立即加锁
final void lock() { if (compareAndSetState(0, 1)) //尝试立即加锁 setExclusiveOwnerThread(Thread.currentThread()); else //立即加锁失败 acquire(1); } -
立即加锁失败后等待acquire(1),tryAcquire实现
protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } // 在NonfairSync的父类Sync中实现 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; }
-
-
非公平/公平锁的释放使用同一个tryRelease
- tryLock() --> Sync.nonfairTryAcquire(1)
- unlock() --> Sync.tryRelease(1)
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
-
创建条件队列:直接返回AQS的内部类ConditionObject
AQS底层:
等待队列:
- AQS的等待队列为CLH队列的变体–> 双端队列
- 每个等待acquire的线程将作为一个节点在等待队列中排队
- Node类 – 每个节点代表一个在队列中等待获取资源(acquire)的线程
- waitStatus : 当前节点状态(表示线程的状态)
- (0) : 初始化时的默认值
- CANCELLED (1): 该节点所代表的线程被取消(timeout / interrupt)
- SIGNAL (-1): 该节点的后继所表示的线程正被阻塞(表示该节点被释放或取消后,应解除(unpark)其后继的阻塞,让后面的线程acquire())(表示该节点有责任唤醒其后继节点)
- CONDITION (-2): 该节点所代表的线程在condition上等待(该节点在条件队列中)
- PROPAGATE (-3): 指示下一个acquireShared()要无条件的传播
- next: 后驱指针
- prev:前驱指针
- thread:该节点所表示的线程
- nextWaiter:下一个处于CONDITION状态的节点
- waitStatus : 当前节点状态(表示线程的状态)
- 队列头节点head为哨兵(哑节点),其waitStatus有意义,表示当前获取了资源的线程的状态。队首第一个节点(head的后继),成功acquire()后,将取代旧的head。
acquire() – 以独占的方式获取
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt(); //acquireQueued成功获取后,返回中断标记,在此恢复
}
-
首先尝试加锁 tryAcquire(…)
-
若失败则首先将当前线程加入等待队列中 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) { node.prev = pred; if (compareAndSetTail(pred, node)) { //原子操作-比较并设置(通过比较内存位置判断尾是否被其他线程修改) pred.next = node; return node; //设置成功 } } //队列为空 或 设置插入失败时(其他线程竞争),enq(node) enq(node); return node; } private Node enq(final Node node) { for (;;) { Node t = tail; if (t == null) { // Must initialize //队列为空 尝试初始化队列,插入哨兵节点 if (compareAndSetHead(new Node())) tail = head; } else { // 加入到尾后 node.prev = t; if (compareAndSetTail(t, node)) { t.next = node; return t; } } } } -
acquireQueued(…)将以独占的,不可中断的模式,尝试在该节点上"获取" (使得当前线程为独占的线程)
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; //自旋 for (;;) { //获取前驱p final Node p = node.predecessor(); // 如果该节点(代表当前线程)是第一个有效节点(队列中第一个正在等待的节点),则尝试获取(tryAcquire) if (p == head && tryAcquire(arg)) { //获取成功,让该节点成为哨兵节点("出队") setHead(node); p.next = null; // help GC failed = false; return interrupted; } // 执行至此的两种可能: p != head 当前节点不是第一个有效节点; tryAcquire() 失败(被非公平地抢占了(要是公平的话不能插队,只有队首的节点才可以获取锁)) // shouldParkAfterFailedAcquire() 判断是否应该阻塞,避免自旋占用CPU // 若应被阻塞,则parkAndCheckInterrupt() 阻塞当前线程,并在线程恢复后返回中断状态 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) //若阻塞恢复后发现被中断 interrupted = true; } } finally { if (failed) //获取失败,将节点标记为取消状态 cancelAcquire(node); } } //更新该节点和等待队列,判断是否应阻塞(返回true --> 阻塞) private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { //前驱节点的等待状态 int ws = pred.waitStatus; if (ws == Node.SIGNAL) //前驱的状态为SIGNAL,表示其前驱正在活跃 --> 该节点的线程被应该被阻塞,等待前驱释放或被取消 return true; //需要阻塞 if (ws > 0) { //前驱节点状态大于0,表示其前驱节点已被取消,将其弹出 //弹出所有被取消的前驱节点(线程) do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else { //0 或 PROPAGATE /* * 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. */ //将前驱状态设置为SIGNAL,表示该线程等待前驱节点释放或被取消 compareAndSetWaitStatus(pred, ws, Node.SIGNAL); //返回false,在阻塞前再尝试一次 } return false; } //挂起当前线程,并返回中断标记 private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); } -
cancelAquire(node) – 获取失败,取消当前节点(线程)的获取操作
//Cancels an ongoing attempt to acquire 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; //在此设置为CANCELLED后,就可能被acquire()中调用的shouldParkAfterFailedAcquire()弹出 // 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 (node == tail && compareAndSetTail(node, pred)) { compareAndSetNext(pred, predNext, null); } else { // 该节点不是尾节点的情况 // 如果该节点被取消前不是第一个(head的后续)有效节点(在等待的),则将自己的有效前驱的状态设为SIGNAL,用以表示自己的有效后继等待唤醒 // 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))) && //其有效前驱没有被设为SIGNAL,则尝试设置 pred.thread != null) { Node next = node.next; if (next != null && next.waitStatus <= 0) compareAndSetNext(pred, predNext, next); } else { // 该节点是第一个有效的节点,则唤醒其后继 unparkSuccessor(node); } node.next = node; // help GC } }
release()
- 以独占模式释放->取消一个或多个线程的阻塞
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
- unparkSuccessor(node) – 唤醒一个node的未被取消的后继节点(线程)
- 从尾部向前遍历寻找第一个未被取消的节点的原因:
- addWaiter时先设置prev再设置next,并不是原子操作
- 取消节点时,断开了被取消节点的next指针,并未断开prev指针
- 从尾部向前遍历寻找第一个未被取消的节点的原因:
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) //SIGNAL\CONDITION\PROPAGATE
compareAndSetWaitStatus(node, ws, 0); //设为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);
}
ConditionObject
AQS的内部类,实现了默认的条件队列
/** First node of condition queue. */
private transient Node firstWaiter;
/** Last node of condition queue. */
private transient Node lastWaiter;
-
await() – 阻塞线程,加入条件队列,等待signal()唤醒
public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); //添加将当前线程加入 条件队列 Node node = addConditionWaiter(); //释放并保存状态,也会 等待队列 唤醒下一个节点 int savedState = fullyRelease(node); //阻塞,等待被唤醒 int interruptMode = 0; while (!isOnSyncQueue(node)) { //判断当前节点(线程),是否在等待队列中等待acquire,若是则可以跳出在condition上的等待 LockSupport.park(this); //checkInterruptWhileWaiting:若被signal前中断,返回THROW_IE; 若被signal后中断,返回REINTERRUPT; 未被中断返回0 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } //acquireQueued(node, savedState): 恢复state,并等待acquire if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); } //加入condition的等待队列(条件队列) private Node addConditionWaiter() { Node t = lastWaiter; // If lastWaiter is cancelled, clean out. if (t != null && t.waitStatus != Node.CONDITION) { unlinkCancelledWaiters(); t = lastWaiter; } Node node = new Node(Thread.currentThread(), Node.CONDITION); if (t == null) firstWaiter = node; else t.nextWaiter = node; lastWaiter = node; return node; } //释放等待队列中的节点 final int fullyRelease(Node node) { boolean failed = true; try { int savedState = getState(); if (release(savedState)) { failed = false; return savedState; } else { throw new IllegalMonitorStateException(); } } finally { if (failed) node.waitStatus = Node.CANCELLED; } } /** * Returns true if a node, always one that was initially placed on * a condition queue, is now waiting to reacquire on sync queue. * @param node the node * @return true if is reacquiring */ final boolean isOnSyncQueue(Node node) { if (node.waitStatus == Node.CONDITION || node.prev == null) return false; if (node.next != null) // If has successor, it must be on queue return true; /* * node.prev can be non-null, but not yet on queue because * the CAS to place it on queue can fail. So we have to * traverse from tail to make sure it actually made it. It * will always be near the tail in calls to this method, and * unless the CAS failed (which is unlikely), it will be * there, so we hardly ever traverse much. * (-->addWaiter中插入节点的方式) */ //从尾向前搜索节点 return findNodeFromTail(node); } //从尾向前寻找node,返回是否储存在 private boolean findNodeFromTail(Node node) { Node t = tail; for (;;) { if (t == node) return true; if (t == null) return false; t = t.prev; } } -
signal() – 唤醒一个在条件队列中等待的线程
public final void signal() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); //唤醒等待队列中第一个节点(线程) Node first = firstWaiter; if (first != null) doSignal(first); } //移除被取消的节点,直到遇到一个未被取消的节点或null。第一个遇到的节点将会被转移至等待队列。 private void doSignal(Node first) { do { if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; //断开后继指针 } while (!transferForSignal(first) && //直到转移成功一个未被取消的节点 (first = firstWaiter) != null); //或为空 } //将节点从条件队列转移到等待队列 (condition queue -> sync queue) final boolean transferForSignal(Node node) { /* * If cannot change waitStatus, the node has been cancelled. */ if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; //在条件队列中的node可能取消---> 失败. doSignal中将继续找下一个节点 /* * Splice onto queue and try to set waitStatus of predecessor to * indicate that thread is (probably) waiting. If cancelled or * attempt to set waitStatus fails, wake up to resync (in which * case the waitStatus can be transiently and harmlessly wrong). */ Node p = enq(node); //自旋尝试加入尾部 (addWaiter方法也使用enq),返回其前驱 int ws = p.waitStatus; if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) //将其前驱节点的状态改为signal(要求其释放之后,唤醒当前节点) LockSupport.unpark(node.thread); //失败,则直接唤醒 return true; }
170万+

被折叠的 条评论
为什么被折叠?



