脚本宝典收集整理的这篇文章主要介绍了

高并发 – AbstractQueuedSynchronizer

脚本宝典小编觉得挺不错的,现在分享给大家,也给大家做个参考,希望能帮助你少写一行代码,多一份安全和惬意。

温馨提醒

  1. AbstractQueuedSynchronizer队列是CLH队列的变种,CLH队列等待采用自旋,AQS的队列等待采用LockSupport#park。
  2. Node.waitStatus表示对应线程是否应当阻塞,
  3. head节点是正占有锁的线程的,其thread值为null,处于head后驱节点的线程才会去tryAcquire,tryAcquire由子类实现。
  4. 入队在tail,出队在head
以下必须要子类实现:
/**
 * exclusive mode 
 */
boolean tryAcquire(int arg) 
/**
 * exclusive mode.
 */
boolean tryRelease(int arg) 
/**
 * shared mode.
 */
int tryAcquireShared(int arg)
/**
 * shared mode.
 */
boolean tryReleaseShared(int arg) 
/**
 * Returns true if synchronization is held exclusively with
 * respect to the current (calling) thread.  
 */
boolean isHeldExclusively() 

独占模式acquire

private Node enq(final Node node) {
// 无限循环,即step 1返回false(有别的线程将它的node连接到tail)也会重新将node连接到tail
    for (;;) {
        Node t = tail;
        if (t == null) {     // new一个不带任何状态的Node作为头节点
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {    // step 1
                t.next = node;
                return t;    // 返回当前tail
            }
        }
    }
}


private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    //-- 和#enq逻辑比,只是取消了循环,为了更快?
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
//--
    enq(node);
    return node;    // 返回当前线程的node
}


final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
    // 无限循环,直到当前线程node的前驱node是head,否则对于node状态为SIGNAL的线程会park
        for (;;) {
            final Node p = node.predecessor();
        // 如果当前线程node的前驱是head
            if (p == head && tryAcquire(arg)) {
            // head = node; 从而让其他线程也能走入该if
        // node.thread = null; 所以head永远是一个不带Thread的空节点 
        // node.prev = null;
                setHead(node);        
                p.next = null;     // 配合上面的 node.prev = null; for GC
                failed = false;
                return interrupted;
            }
        // 判断在tryAcquire失败后是否应该park,若是,则执行park
            if (shouldParkAfterFailedAcquire(p, node) && 
          // LockSupport#park,返回Thread#interrupted
          parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}


private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
// 表示当前节点应当park
    if (ws == Node.SIGNAL) return true;
// 当前节点不断向前找,直到找到一个前驱节点waitStats不是CANCELLED的为止(状态值里面只有CANCELLED是大于0的)
    if (ws > 0) {
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
    // 中间CANCELLED的node作废
        pred.next = node;
    } 
// 0 or PROPAGATE 需要设置为SIGNAL,但仍然返回false,即don’t park
else { 
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}


// Acquires in exclusive mode, ignoring interrupts
public final void acquire(int arg) {
// 这里提前tryAcquire为了省去入队列操作,提高性能,因为大部分情况下可能都没有锁竞争
    if (!tryAcquire(arg) &&
    // 入队列,返回当前线程中断状态
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

独占模式release

public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)    // step 1
            unparkSuccessor(h);
        return true;
    }
    return false;
}


private void unparkSuccessor(Node node) {
   
    int ws = node.waitStatus;
// 这里是SIGNAL,将head的waitStatus设为0,是为了不重复step 1
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    Node s = node.next;
// 如果head(当前线程)无后驱node,或后驱node为CANCELLED
    if (s == null || s.waitStatus > 0) {
        s = null;
    // 从链表tail开始遍历,取出非CANCELLED的node
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
// 非CANCELLED的线程unpark,继续#acquireQueued的for循环
    if (s != null)
        LockSupport.unpark(s.thread);
}















总结

以上是脚本宝典为你收集整理的

高并发 – AbstractQueuedSynchronizer

全部内容,希望文章能够帮你解决

高并发 – AbstractQueuedSynchronizer

所遇到的程序开发问题,欢迎加入QQ群277859234一起讨论学习。如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典网站推荐给程序员好友。 本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。

80%的人都看过