jdk源码解析七之Condition

Condition

在这里插入图片描述

主要看java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject

newCondition

    public Condition newCondition() {
        return sync.newCondition();
    }
       final ConditionObject newCondition() {
            return new ConditionObject();
        }

await

       public final void await() throws InterruptedException {
            //中断处理
            if (Thread.interrupted())
                throw new InterruptedException();

            //添加下一个节点到等待队列
            Node node = addConditionWaiter();
            //阻塞时候,会释放锁
            int savedState = fullyRelease(node);
            //1) 当在被通知前被中断则将中断模式设置为THROW_IE;
            // 2) 当在被通知后则将中断模式设置为REINTERRUPT(因为acquireQueued不会响应中断)。
            int interruptMode = 0;
            //如果不在同步队列,则阻塞
            while (!isOnSyncQueue(node)) {
                //阻塞当前线程
                //在另一个线程调用sign和unlock之后唤醒
                //调用sign,将当前等待线程添加到同步线程
                //然后调用unlock释放同步线程
                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
            //删除状态不为CONDITION的节点
                unlinkCancelledWaiters();
            //根据中断模式抛出异常
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }

   private Node addConditionWaiter() {
            //获取上一个等待节点
            Node t = lastWaiter;
            // If lastWaiter is cancelled, clean out.
            if (t != null && t.waitStatus != Node.CONDITION) {
                unlinkCancelledWaiters();
                t = lastWaiter;
            }
            //创建一个新的节点,并标记CONDITION
            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;
        }
    }

  final boolean isOnSyncQueue(Node node) {
        //如果节点在条件队列或者节点前置为null,则阻塞
        //prev为null的时候,说明是头节点,而头结点一般是空node,所以不可能是头结点
        //name也就是处于transferForSignal方法中compareAndSetWaitStatus和enq之间的中间状态
        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.
         */
        //状态不是CONDITION,且前置节点不为null,后置节点为null,可能是尾节点,则从后查找
        //从后到前查找是否有node,如果没有说明还正在添加则阻塞
        //也就是enq调用compareAndSetTail存在并发修改失败
        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;
        }
    }

  private int checkInterruptWhileWaiting(Node node) {
            /*
            没有异常,返回0
            中断在通知之前,THROW_IE
            中断在通知之后,REINTERRUPT
             */
            return Thread.interrupted() ?
                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
                0;
        }

  final boolean transferAfterCancelledWait(Node node) {
        //当前节点状态为CONDITION,中断在通知之前
        //设置状态为0,将取消的线程添加到同步队列中
        if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
            enq(node);
            return true;
        }
        /*
         * If we lost out to a signal(), then we can't proceed
         * until it finishes its enq().  Cancelling during an
         * incomplete transfer is both rare and transient, so just
         * spin.
         */
        /*
        节点不是CONDITION状态,这说明中断在通知之后
        自旋添加到队列中
         */
        while (!isOnSyncQueue(node))
            Thread.yield();
        //线程在通知之后被取消
        return false;
    }


 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)) {
                    //设置头结点为当前节点,以及清空当前节点的pre和thread
                    setHead(node);
                    //释放GC
                    p.next = null; // help GC
                    //标记正常执行
                    failed = false;
                    return interrupted;
                }
                //检查并修改一个节点的状态,当该节点获取锁失败时。返回true如果线程需要阻塞。
                if (shouldParkAfterFailedAcquire(p, node) &&
                        //这里执行阻塞
                    parkAndCheckInterrupt())
                    //标记已中断
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

  private void unlinkCancelledWaiters() {
            //删除状态不为CONDITION的节点
            //trail ->t->next
            Node t = firstWaiter;
            //记录上一个状态为CONDITION的节点
            Node trail = null;
            while (t != null) {
                Node next = t.nextWaiter;
                if (t.waitStatus != Node.CONDITION) {
                    t.nextWaiter = null;
                    if (trail == null)
                        firstWaiter = next;
                    else
                        //删除t节点
                        trail.nextWaiter = next;
                    if (next == null)
                        lastWaiter = trail;
                }
                else
                    trail = t;
                t = next;
            }
        }

 private void reportInterruptAfterWait(int interruptMode)
            throws InterruptedException {
            //抛出中断异常
            if (interruptMode == THROW_IE)
                throw new InterruptedException();
            else if (interruptMode == REINTERRUPT)
                //中断
                selfInterrupt();
        }

signal

 public final void signal() {
            //发送信号的是否是当前线程,如果不是则异常
             //确保signal在lock之后,且同一个线程
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            //获取第一个等待节点
            Node first = firstWaiter;
            if (first != null)
                //发送信号
                doSignal(first);
        }


   private void doSignal(Node first) {
            do {
                //删除first节点,并设置firstWaiter为下一个节点
                //如果下一个节点为null,则清空lastWaiter
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                //清空first下一个节点
                first.nextWaiter = null;

            } while (
                    //将删除的first节点添加到同步队列
                    //如果添加失败,说明已经有其他线程添加成功了
                    //却白first不为null,再次遍历
                    !transferForSignal(first) &&
                     (first = firstWaiter) != null);
        }

 final boolean transferForSignal(Node node) {
        /*
         * If cannot change waitStatus, the node has been cancelled.
         */
        //修改状态为普通状态,如果失败,说明其他线程正在执行添加操作
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;

        /*
         * 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添加到同步队列最后,且返回上一个节点
        Node p = enq(node);
        //获取入队前前置节点状态
        int ws = p.waitStatus;
        //前置节点为取消状态的时候,也就是说他不会在被唤醒,如果当前线程执行unlock执行unpark操作的时候,唤醒的是一个取消节点
        //而这不是我们愿意看到的,我们希望唤醒的是一个正常节点,这里提前唤醒下一个正常节点线程.在正常节点被唤醒后,会竞争锁,竞争锁成功后,会删除取消的节点
        //前置节点为取消状态,直接唤醒
        //或者为非取消状态则修改为SIGNAL,如果失败则唤醒
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            //唤醒当前线程
            LockSupport.unpark(node.thread);
        //添加同步队列成功
        return true;
    }

signalAll

    public final void signalAll() {
            //非当前获取独占锁线程异常
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            //获取第一个等待节点
            Node first = firstWaiter;
            if (first != null)
                //遍历添加所有等待节点到同步队列
                doSignalAll(first);
        }

  private void doSignalAll(Node first) {
            lastWaiter = firstWaiter = null;
            do {
                Node next = first.nextWaiter;
                first.nextWaiter = null;
                transferForSignal(first);
                first = next;
            } while (first != null);
        }

总结

await时,会释放锁
在这里插入图片描述

await有2个阻塞状态,第一个阻塞状态等待当前节点添加到同步队列
第二个阻塞状态是竞争锁.
在这里插入图片描述
ConditionObject维护了2个节点,当await时将节点添加到等待队列中
当signal时,将队列节点添加到同步队列head和tail中.在执行unlock的时候被唤醒.
但是在signal
时,如果上一个节点出现取消状态或者上一个同步队列节点修改状态失败,则提前唤醒当前节点
在这里插入图片描述
在这里插入图片描述
对CAS中间状态的维护
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值