java conditions源码分析

await

public final void await() throws InterruptedException {
    // 1.如果当前线程被中断,则抛出中断异常
    if (Thread.interrupted())
        throw new InterruptedException();
    // 2.创建一个线程的节点,并放到Condition队列中去,等待着signal来唤起它
    Node node = addConditionWaiter();
    // 3.调用tryRelease,释放当前线程的锁,这样别的线程可以获取锁,不会出现死锁了
    long savedState = fullyRelease(node);
    int interruptMode = 0;
    // 4. 判断当前现在是不是在等待锁的队列中。如果不在,就park当前线程(这个时候说明线程还在等signal,就不线程给阻塞了,等待signal),如果在,就退出循环,这个时候如果被中断,那么就退出循环
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    // 5.这个时候线程已经被signal()或者signalAll()操作给唤醒了,退出了4中的while循环,这里就尝试去获得锁。 
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null)
        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;
            }
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
        }

首先看链表的最后一个节点的状态是不是为Node.CONDITION,如果不是的,那么就清理下整个链表中的非condition状态的节点,然后利用当前线程创建一个节点并放到链表的最后,并返回节点。

我们在看下清理链表的代码

        private void unlinkCancelledWaiters() {
            Node t = firstWaiter;
            Node trail = null;
            while (t != null) {
                Node next = t.nextWaiter;
                if (t.waitStatus != Node.CONDITION) {
                    t.nextWaiter = null;
                    if (trail == null)
                        firstWaiter = next;
                    else
                        trail.nextWaiter = next;
                    if (next == null)
                        lastWaiter = trail;
                }
                else
                    trail = t;
                t = next;
            }
        }

这个函数就是遍历整个链表,把链表中状态不是Node.CONDITION的线程节点给删除。保证所有的线程都是等待这个条件的。

释放锁

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

调用release释放锁,如果释放不成功,把node.waitstatus=cancelled,表示线程不需要等待了。

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

首先尝试去释放锁,如果成功唤起一个等待的线程

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

可重入锁通过status 表示当前线程获取几次锁,这个需要释放锁的话,就是需要把减去releases, 后面有个判断获得锁的线程释放当前线程(当然是的,否则怎么释放呢?)。 然后看减去后是否为0,如果0的话,释放成功并把当前锁的线程设置为null。设置状态并返回是否释放成功。

然后看下unparkSuccessor

   private void unparkSuccessor(Node node) {
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }

唤起后继一个节点:首先把当前线程状态设置成等待锁的,然后在后续节点中找到一个线程,然后进行唤起(为什么从队列最后往前遍历,这里也不明白)

判断是否在同步等待队列上

    final boolean isOnSyncQueue(Node node) {
        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.
         */
        return findNodeFromTail(node);
    }

看node对应的线程是否在同步队列中的:
- 如果线程状态是CONDITION,也就是还没有收到signal消息,肯定不会去竞争锁的,一定不在同步队列中。 如果不是CONDITION,那么就看下prev,如果是空的,一定不在队列中
- 看下next非空,也就是有后续的节点,那一定已经放到了队列中了
- 走到了这里,条件一和二都不成立,应该是线程拿到了signal信号,而尝试把节点放到队列后面去的时候,cas失败还在尝试中,现在如果好了的话,那么节点一定排在很后面,我们就从后往前去便利链表。

    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) {
            return Thread.interrupted() ?
                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
                0;
        }

如果真的被中断了,那么尝试把节点的状态从condition到0,并把节点放到同步队列最后去

 final boolean transferAfterCancelledWait(Node node) {
        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.
         */
        while (!isOnSyncQueue(node))
            Thread.yield();
        return false;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值