前言:将AQS的知识点做一个总结. 梳理了独占共享两种模式下的加解锁流程,以及两种锁的异同点. 适合日后复习
目录
该抽象类主要实现了:在获取锁失败时,线程如何阻塞,如何唤醒.。使用的逻辑结构为【同步等待队列】
如何获取锁,以及获取锁是成功还是失败,由子类去定义。AQS则提供了获取锁失败后,入队/出队、阻塞/唤醒的实现。
队列何时初始化?【尝试加锁】失败后,在addWaiter方法中,若tail为空,则新建一个Node作为头结点
何时入队?【尝试加锁】失败后,尾插到队尾
何时出队?当队列中有新的结点加锁成功时,原head指向的结点出队,随后head指向新的结点
尝试加锁,成功则方法结束;加锁失败则将此线程尾插到"同步等待"队列
- // 加锁
- public final void acquire(int arg) {
- if (!tryAcquire(arg) &&
- acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
- selfInterrupt();
- }
protected boolean tryAcquire(int arg) :tryAcquire方法由其实现类实现:返回是否成功获取锁( 即是否成功将state由0变为1 )
private Node addWaiter(Node mode) :将当前线程封装为Node, 并将其插入到队尾. 没初始化队列会先初始化
final boolean acquireQueued(final Node node, int arg) :加锁成功则跳出方法,执行业务逻辑;或park此结点
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) :pred.ws == -1,则返回true,否则CAS设置pred.ws == -1。并把CANCELLED的结点移除队列
尝试解锁,解锁失败则直接返回false,成功则唤醒"同步等待"队列中第一个满足要求的结点,并返回true
- // 解锁
- public final boolean release(int arg) {
- if (tryRelease(arg)) {
- Node h = head;
- if (h != null && h.waitStatus != 0) // ≠0实际上就只能为-1
- unparkSuccessor(h); // 唤醒后继结点
- return true;
- }
- return false;
- }
private void unparkSuccessor(Node node) :node.waitStatus<0 且 有后继结点,则unpark其后继【LockSupport.unpark(node.next.thread)】;否则取最靠前的、waitStatus<=0的结点
尝试获取锁,返回负数则表示需要进行"阻塞"
- public final void acquireShared(int arg) {
- if (tryAcquireShared(arg) < 0)
- doAcquireShared(arg);
- }
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) :pred.ws == -1,则返回true,否则CAS设置pred.ws==-1。并把CANCELLED的结点移除队列.【同独占锁调用的相同】
private void setHeadAndPropagate(Node node, int propagate) :设置头节点并传播唤醒,也就是说,当一个结点加共享锁成功,它会执行unparkSuccessor(Node node),进而唤醒后继结点。具体实现主要在doReleaseShared()方法👇
- private void setHeadAndPropagate(Node node, int propagate) {
- Node h = head; // Record old head for check below
- setHead(node);
-
- // propagate表示剩余的资源.
- if (propagate > 0 || h == null || h.waitStatus < 0 ||
- (h = head) == null || h.waitStatus < 0) {
- Node s = node.next;
- if (s == null || s.isShared())
- doReleaseShared();
- }
- }
-
-
- /*
- 简而言之:不断执行unparkSuccessor(h)操作,来唤醒后继结点,
- 退出条件为h == head,表示如果没有新的结点来代替现有头结点则退出
- unparkSuccessor方法同独占锁
- */
- private void doReleaseShared() {
- for (;;) {
- Node h = head;
- if (h != null && h != tail) {
- int ws = h.waitStatus;
- if (ws == Node.SIGNAL) {
- if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
- continue; // loop to recheck cases
- unparkSuccessor(h);
- }
- else if (ws == 0 &&
- !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
- continue; // loop on failed CAS
- }
- if (h == head) // loop if head changed
- break;
- }
- }
尝试解锁,失败返回false;成功则执行doReleaseShared(),该方法会唤醒后继结点
- public final boolean releaseShared(int arg) {
- if (tryReleaseShared(arg)) {
- doReleaseShared();
- return true;
- }
- return false;
- }
共同点:尝试加锁,失败则addWaiter并自旋(加锁->阻塞)
独占锁:boolean tryAcquire,返回true表示加锁成功
共享锁:int tryAcquireShared,返回≥0代表成功
共同点:首次尝试加锁失败,调用addWaiter,并自旋(加锁->阻塞)
在自旋尝试加锁的过程中,若加锁成功,
独占模式下将当前结点设为头结点:head = node,失败则阻塞;
共享模式下,不仅会将当前结点设为头结点,还会在合适条件下(如还有剩余资源),调用doReleaseShared(),来继续唤醒其后继结点。
这也是两种模式最关键的不同
独占模式下,只有release时才会尝试unpark头结点的后继结点;
共享模式下,除release时会unpark外,线程在自旋时获取到锁后,也可能会unpark.
个人理解:doReleaseShared()方法的自旋目的在于,在队列有结点出队时,快速通知下一下结点,使其unpark.
共同点:唤醒后继结点
独占模式下,head为-1则直接进行unparkSuccessor(h),随后方法结束
共享模式下,在doReleaseShared()中调用unparkSuccessor(h).
代码如下,其中for循环的部分为doReleaseShared
- static final class Node {
- volatile int waitStatus
- }
-1:表明后继结点需要被唤醒;结点想要被park,也需要其前驱结点为-1。在上述加解锁的方法里被置为-1的时机有:
0:初始状态. 结点刚创建时的状态。在上述加解锁的方法里被置为0的时机有:
猜测:让即将被唤醒的线程成为头节点后,ws为0,这样后续结点可以多一次循环拿锁的机会,减小被park的概率
-
- public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
- private volatile int state;
- }
独占模式:0:空闲;1:被占有;≥1:被重入的次数
共享模式:state:资源数,0表示没有可用资源
加锁:区分公平和非公平两种模式
- // ReentrantLock类
- public void lock() {
- sync.acquire(1);
- }
-
- ------------------------------非公平锁tryAcquire------------------------------
- // NonfairSync类
- protected final boolean tryAcquire(int acquires) {
- return nonfairTryAcquire(acquires);
- }
-
- // 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;
- }
-
- ------------------------------公平锁tryAcquire------------------------------
- // FairSync类
- 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;
- }
解锁:公平与非公平模式都是调Sync的tryRelease
- // ReentrantLock类
- public void unlock() {
- sync.release(1);
- }
-
- // Sync类
- 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;
- }
加锁:区分公平和非公平两种模式
- // Semaphore类
- public void acquireUninterruptibly() {
- sync.acquireShared(1);
- }
-
- ------------------------------非公平锁tryAcquire------------------------------
- // NonfairSync类
- protected int tryAcquireShared(int acquires) {
- return nonfairTryAcquireShared(acquires);
- }
-
- // Sync类
- final int nonfairTryAcquireShared(int acquires) {
- for (;;) {
- int available = getState();
- int remaining = available - acquires;
- if (remaining < 0 ||
- compareAndSetState(available, remaining))
- return remaining;
- }
- }
-
- ------------------------------公平锁tryAcquire------------------------------
- // FairSync类
- protected int tryAcquireShared(int acquires) {
- for (;;) {
- if (hasQueuedPredecessors())
- return -1;
- int available = getState();
- int remaining = available - acquires;
- if (remaining < 0 ||
- compareAndSetState(available, remaining))
- return remaining;
- }
- }
解锁:公平与非公平模式都是调Sync的tryRelease
- // Semaphore类
- public void release(int permits) {
- if (permits < 0) throw new IllegalArgumentException();
- sync.releaseShared(permits);
- }
-
- // Sync类
- protected final boolean tryReleaseShared(int releases) {
- for (;;) {
- int current = getState();
- int next = current + releases;
- if (next < current) // overflow
- throw new Error("Maximum permit count exceeded");
- if (compareAndSetState(current, next))
- return true;
- }
- }
countDownLatch在加锁时,只看state是否为0,无关公平与否, 因此只有公平模式
- ---------------------------------加锁---------------------------------
-
- // CountDownLatch类
- public void await() throws InterruptedException {
- sync.acquireSharedInterruptibly(1);
- }
-
- // Sync类
- protected int tryAcquireShared(int acquires) {
- return (getState() == 0) ? 1 : -1;
- }
-
- ---------------------------------解锁---------------------------------
- // CountDownLatch类
- public void countDown() {
- sync.releaseShared(1);
- }
-
- // Sync类
- protected boolean tryReleaseShared(int releases) {
- // Decrement count; signal when transition to zero
- for (;;) {
- int c = getState();
- if (c == 0)
- return false;
- int nextc = c - 1;
- if (compareAndSetState(c, nextc))
- return nextc == 0;
- }
- }