Condition学习

一、Condition作用

   Condition 是一个多线程协调通信的工具类,可以让某些线程一起等待某个条件(condition)(等待其他线程唤醒),只有满足条件时,线程才会被唤醒。

二、Condition构造方法

使用ReentrantLock的继承AQS的内部类Sync一个方法

 返回了AQS的内部类ConditionObject的一个对象。

三、ConditionObject

//condition queue的头指针和尾指针
private transient Node firstWaiter;
private transient Node lastWaiter;  
//从头开始遍历,将cancel状态的节点清理
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;
    }
}

 addConditionWaiter()方法创建一个代表当前线程的Node到条件队列的尾部

private Node addConditionWaiter() {
    Node t = lastWaiter;
    // If lastWaiter is cancelled, clean out.
    if (t != null && t.waitStatus != Node.CONDITION) {
        // 如果节点不在条件队列中的话
        // 从条件队列中清除已取消的节点的链接
        unlinkCancelledWaiters();
        t = lastWaiter;
    }
    // 创建一个hold住当前线程的Node节点
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    if (t == null)
        firstWaiter = node;
    else
        t.nextWaiter = node;
    lastWaiter = node;
    return node;
}

 await()方法:会释放锁资源以及CPU资源 

public final void await() throws InterruptedException {
    //如果当前线程的中断标识符是true,则将它的中断标识符设置为false,并返回true
    //抛出中断异常,否则返回false
    if (Thread.interrupted())
        throw new InterruptedException();
    // 1. 清除非CONDITION状态的节点,创建一个Node节点并将其添加到条件队列的尾部
    Node node = addConditionWaiter(); 
    // 2. 释放当前节点的独占模式占用情况,并且解除后继节点的阻塞状态
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    // 3. 判断是否不在同步队列中(head、tail)
    while (!isOnSyncQueue(node)) {
        // 不在同步队列中则挂起
        // 直到其他线程调用unpark、中断时才解除休眠
        LockSupport.park(this);
        // checkInterruptWhileWaiting检查是否有中断,如果在信号之前中断,返回THROW_IE;如果在信号之后中断,返回REINTERRUPT;如果没有中断,返回0。
        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);
}

先插入AQS的CLH队列。这些线程通过CAS操作抢夺state,以表明是否成功抢占锁。

其中state为0表示当前没有线程获取锁。

fullyRelease()会释放该线程的所有锁,getState()会获取当前线程获取锁的次数。

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

调用AQS的方法release尝试释放所有锁,释放成功,会将当前的AQS的FIFO同步队列的第一个Node元素唤醒(通过unparkSuccessor方法的LockSupport.unpark(s.thread)唤醒)。

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

 调用的ReentrantLock中的tryRelease释放所有锁资源

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;
        }
private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);
        Node s = node.next;
        //如果第二个节点的waitStatus大于零,则为1表示节点被取消
        //下面的if会找到离head节点最近的waitStatus等于-1的节点将其唤醒    
        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) // 如果存在后继则肯定在同步队列中
        return true;
    // node.prev 可以是非空的,但是因为CAS可能会失败所以还没有在队列中。
    // 所以需要从tail开始遍历确保真实这样做的。
    // 调用这个方法时,总是在tail附近,除非CAS失败了(不太可能),所以很少会遍历
    return findNodeFromTail(node);
}


// 遍历,在同步队列中则返回true
private boolean findNodeFromTail(Node node) {
    Node t = tail;
    for (;;) {
        if (t == node)
            return true;
        if (t == null)
            return false;
        t = t.prev;
    }
}

signal()方法

public final void signal() {
    // 检查独占模式下占有的线程是否为当前线程
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    
    // 目标节点设置为等待队列中的头节点
    Node first = firstWaiter;
    if (first != null)
        // 删除和传输节点,直到到达一个不可删除的节点或者null
        doSignal(first);
}

private void doSignal(Node first) {
    do {
        // 1. 如果当前被通知信号的节点(等待队列中的头节点)的下一个节点为null的话,则尾节点置为null
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        
        // 2. 当前被通知信号的节点的下一个节点置为null
        first.nextWaiter = null;
    } while (!transferForSignal(first) &&
             (first = firstWaiter) != null);
}

// 从条件队列传输一个节点到同步队列,成功则返回true
final boolean transferForSignal(Node node) {
    // 如果无法变更waitStatus,说明节点已经被取消了
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
        return false;
    
    // 将firstWaiter入队列,并且置为tail的后继
    Node p = enq(node);
    int ws = p.waitStatus;
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        // 将tail置为Node.SIGNAL,并解除其后继即firstWaiter的阻塞状态
        LockSupport.unpark(node.thread);
    return true;
}

// 将节点入队列,必要时初始化
// head、tail 是同步队列的首尾节点
private Node enq(final Node node) {
    for (;;) {
        // 死循环处理
        Node t = tail;
        if (t == null) { // Must initialize
            if (compareAndSetHead(new Node())) // tail为null,则表示同步队列是空的,初始化head节点
                tail = head; // 并且tail设置和head一样
        } else {
            // 将firstWaiter的前置节点指向tail
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                // 将tial的后置指向firstWaiter并返回tail节点
                t.next = node;
                return t;
            }
        }
    }
}

// 硬件级别的原子控制; headOffset表示head头的内存中的偏移位置
// 4各参数:对象、偏移位置、期望值、目标修改值
private final boolean compareAndSetHead(Node update) {
    return unsafe.compareAndSwapObject(this, headOffset, null, update);
}

private final boolean compareAndSetTail(Node expect, Node update) {
    return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值