欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识

这里重点就是第6行的transferForSignal方法: 昆山软件开发 final boolean transfe

点击: 次  来源:宝鼎软件 时间:2017-08-16

原文出处: 五月的仓颉

共享模式acquire实现流程

上文我们讲授了AbstractQueuedSynchronizer独有模式的acquire实现流程,本文一气呵成继承看一下AbstractQueuedSynchronizer共享模式acquire的实现流程。持续两篇文章的进修,也可以比拟独有模式acquire和共享模式acquire的区别,劳务派遣管理系统,加深对付AbstractQueuedSynchronizer的领略。

先看一下共享模式acquire的实现,要领为acquireShared和acquireSharedInterruptibly,两者不同不大,区别就在于后者有间断处理惩罚,以acquireShared为例:

public final void acquireShared(int arg) {
      if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
 }

这里就能看出第一个不同来了:独有模式acquire的时候子类重写的要领tryAcquire返回的是boolean,等于否tryAcquire乐成;共享模式acquire的时候,返回的是一个int型变量,判定是否<0。doAcquireShared要领的实现为:

private void doAcquireShared(int arg) {
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head) {
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    if (interrupted)
                        selfInterrupt();
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

我们来阐明一下这段代码做了什么:

  1. addWaiter,把所有tryAcquireShared<0的线程实例化出一个Node,构建为一个FIFO行列,这和独有锁是一样的
  2. 拿当前节点的前驱节点,只有前驱节点是head的节点才气tryAcquireShared,这和独有锁也是一样的
  3. 前驱节点不是head的,执行”shouldParkAfterFailedAcquire() && parkAndCheckInterrupt()”,for(;;)轮回,”shouldParkAfterFailedAcquire()”要领执行2次,当前线程阻塞,这和独有锁也是一样的

确实,共享模式下的acquire和独有模式下的acquire大部门逻辑差不多,最大的不同在于tryAcquireShared乐成之后,独有模式的acquire是直接将当前节点配置为head节点即可,共享模式会执行setHeadAndPropagate要领,顾名思义,即在配置head之后多执行了一步propagate操纵。setHeadAndPropagate要领源码为:

private void setHeadAndPropagate(Node node, int propagate) {
    Node h = head; // Record old head for check below
    setHead(node);
    /*
     * Try to signal next queued node if:
     *   Propagation was indicated by caller,
     *     or was recorded (as h.waitStatus) by a previous operation
     *     (note: this uses sign-check of waitStatus because
     *      PROPAGATE status may transition to SIGNAL.)
     * and
     *   The next node is waiting in shared mode,
     *     or we don't know, because it appears null
     *
     * The conservatism in both of these checks may cause
     * unnecessary wake-ups, but only when there are multiple
     * racing acquires/releases, so most need signals now or soon
     * anyway.
     */
    if (propagate > 0 || h == null || h.waitStatus < 0) {
        Node s = node.next;
        if (s == null || s.isShared())
            doReleaseShared();
    }
}

第3行的代码配置重设head,第2行的代码由于第3行的代码要重设head,因此先界说一个Node型变量h得到原head的地点,这两行代码很简朴。

第19行~第23行的代码是独有锁和共享锁最纷歧样的一个处所,我们再看独有锁acquireQueued的代码:

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);
    }
}

这意味着独有锁某个节点被叫醒之后,它只需要将这个节点配置成head就完事了,而共享锁纷歧样,某个节点被配置为head之后,假如它的后继节点是SHARED状态的,那么将继承通过doReleaseShared要领实验往后叫醒节点,实现了共享状态的向后流传。

共享模式release实现流程