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


新闻资讯

MENU

软件开发知识
原文出处: zy_lebron

一、Condition的观念

先容

回想 synchronized 要害字,它共同 Object 的 wait()、notify() 系列要领可以实现期待/通知模式。

对付 Lock,通过 Condition 也可以实现期待/通知模式。

Condition 是一个接口。
Condition 接口的实现类是 Lock(AQS)中的 ConditionObject。
Lock 接口中有个 newCondition() 要领,通过这个要领可以得到 Condition 工具(其实就是 ConditionObject)。
因此,通过 Lock 工具可以得到 Condition 工具。

Lock lock  = new ReentrantLock();
Condition c1 = lock.newCondition();
Condition c2 = lock.newCondition();

二、Condition的实现阐明

实现

ConditionObject 类是 AQS 的内部类,实现了 Condition 接口。

public class ConditionObject implements Condition, java.io.Serializable {
        private transient Node firstWaiter;
        private transient Node lastWaiter;
        ...

可以看到,劳务派遣管理系统,期待行列和同部行列一样,昆山软件开发,利用的都是同步器 AQS 中的节点类 Node。
同样拥有首节点和尾节点,
每个 Condition 工具都包括着一个 FIFO 行列。
布局图:

执行后头的判定 退出 <a href=劳务调派信息打点系统 while 说明节点已经在同部行列中" class="aligncenter size-full wp-image-30151" title="condition" src="/uploads/allimg/c181010/153911553c0R0-13F1.jpg" />

期待

挪用 Condition 的 await() 要了解使线程进入期待行列,并释放锁,线程状态变为期待状态。

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)) {
        //阻塞
        LockSupport.park(this);
        //假如已经间断了,则退出
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // clean up if cancelled
            unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
}

阐明上述要领的或许进程:

  1. 将当前线程建设为节点,插手期待行列;
  2. 释放锁,叫醒同部行列中的后继节点;
  3. while轮回判定节点是否放入同部行列:
  • 没有放入,则阻塞,继承 while 轮回(假如已经间断了,则退出)
  • 放入,则退出 while 轮回,执行后头的判定
    1. 退出 while 说明节点已经在同部行列中,挪用 acquireQueued() 要领插手同步状态竞争。
    2. 竞争到锁后从 await() 要领返回,即退出该要领。

    执行后头的判定 退出 <a href=劳务调派信息打点系统 while 说明节点已经在同部行列中" class="aligncenter size-full wp-image-30152" title="enterCon" src="/uploads/allimg/c181010/153911553c40F-24631.png" />

    addConditionWaiter() 要领:

    private Node addConditionWaiter() {
        Node t = lastWaiter;
        if (t != null && t.waitStatus != Node.CONDITION) {
            //排除条件行列中所有状态不为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;
    }

    进程阐明:同部行列的首节点移动到期待行列。插手尾节点之前会排除所有状态不为 Condition 的节点。

    通知

    挪用 Condition 的 signal() 要领,可以叫醒期待行列的首节点(期待时间最长),叫醒之前会将该节点移动到同部行列中。

    public final void signal() {
        //判定是否获取了锁
        if (!isHeldExclusively())
            throw new IllegalMonitorStateException();
        Node first = firstWaiter;
        if (first != null)
            doSignal(first);
    }

    进程:

    1. 先判定当前线程是否获取了锁;
    2. 然后对首节点挪用 doSignal() 要领。
    private void doSignal(Node first) {
        do {
            if ( (firstWaiter = first.nextWaiter) == null)
                lastWaiter = null;
            first.nextWaiter = null;
        } while (!transferForSignal(first) &&
           (first = firstWaiter) != null);
    }

    进程:

    1. 修改首节点;
    2. 挪用 transferForSignal() 要领将节点移动到同部行列。
    final boolean transferForSignal(Node node) {
        //将节点状态变为0   
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;
        //将该节点插手同部行列
        Node p = enq(node);
        int ws = p.waitStatus;
        //假如结点p的状态为cancel 可能修改waitStatus失败,则直接叫醒
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
    }

    挪用同步器的 enq 要领,劳务派遣管理系统,将节点移动到同部行列,
    满意条件后利用 LockSupport 叫醒该线程。

    执行后头的判定 退出 <a href=劳务调派信息打点系统 while 说明节点已经在同部行列中" class="aligncenter size-full wp-image-30153" title="signalcon" src="/uploads/allimg/c181010/153911553cU30-39107.png" />