[JDK源码]J.U.C-AQS.ConditionObject

Posted L._l

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[JDK源码]J.U.C-AQS.ConditionObject相关的知识,希望对你有一定的参考价值。

ConditionObject内部类

条件变量 ConditionObject 实现了 Condition 接口

变量构造器定义

public class ConditionObject implements Condition, java.io.Serializable 
    //第一个等待节点
    private transient Node firstWaiter;
    //最后一个等待节点
    private transient Node lastWaiter;
    // 重复中断状态位
    private static final int REINTERRUPT =  1;
    //发生异常状态位
    private static final int THROW_IE    = -1;
    
    public ConditionObject()  

await 等待操作

当节点被添加到等待队列后,需要等待条件成立,await相关方法。

//根据外部中断
public final void await() throws InterruptedException 
    if (Thread.interrupted())//是否线程中断
        throw new InterruptedException();//抛出.,
    Node node = addConditionWaiter();//生成一个Node等待节点将其放入条件阻塞队列
    int savedState = fullyRelease(node);//fullyRelease 调用release,释放AQS竞争队列中当前节点后面的等待锁的节点
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) //节点未放入到AQS的竞争队列之前一直阻塞
        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);

//保证线程不可中断的等待
public final void awaitUninterruptibly() 
    Node node = addConditionWaiter();
    //将线程节点从AQS竞争队列中 释放
    int savedState = fullyRelease(node);
    boolean interrupted = false;
    //节点在等待队列, 让线程阻塞 往里放
    while (!isOnSyncQueue(node)) 
        LockSupport.park(this);
        if (Thread.interrupted())
            interrupted = true;
    
    if (acquireQueued(node, savedState) || interrupted)
        selfInterrupt();

下面这三个 和await差不多 多了 时间 ,时间类型

public final long awaitNanos(long nanosTimeout)//超时等待   整体流程和 aiait一样,只是park方法有等待时长
public final boolean awaitUntil(Date deadline)//park 方法换成了 parkUntil 
public final boolean await(long time, TimeUnit unit)

addConditionWaiter原理

//添加等待节点
private Node addConditionWaiter() 
    Node t = lastWaiter;
    // 判断最后一个等待节点是否位空,状态CONDITION 不是unlinkCancelledWaiters方法
    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;

fullyRelease原理

final int fullyRelease(Node node) 
    boolean failed = true;
    try //当前线程的 state状态
        int savedState = getState();
        if (release(savedState)) //释放 并唤醒后继节点
            failed = false;
            return savedState;
         else //失败抛出异常
            throw new IllegalMonitorStateException();
        
     finally 
        if (failed)// 如果失败,那么将节点状态变为CANCELLED即可
            node.waitStatus = Node.CANCELLED;
    

isOnSyncQueue原理

final boolean isOnSyncQueue(Node node) 
    //节点状态CONDITION 前节点不为空   说明不在竞争队列上
    if (node.waitStatus == Node.CONDITION || node.prev == null)
        return false;
    if (node.next != null) //若节点的next节点不为空,那么一定在AQS 竞争队列上
        return true;
    return findNodeFromTail(node);


    private boolean findNodeFromTail(Node node) 
        Node t = tail;//从尾节点开始遍历  找到该节点
        for (;;) 
            if (t == node)
                return true;
            if (t == null)
                return false;
            t = t.prev;
        
    

reportInterruptAfterWait原理

private void reportInterruptAfterWait(int interruptMode)
    throws InterruptedException 
    //根据外部状态 执行不同操作
    if (interruptMode == THROW_IE)
        throw new InterruptedException();
    else if (interruptMode == REINTERRUPT)
        selfInterrupt();

checkInterruptWhileWaiting 原理

private int checkInterruptWhileWaiting(Node node) 
    return Thread.interrupted() ? //线程是否发生了中断   ,正常情况下返回0
        (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
        0;

unlinkCancelledWaiters原理

//从条件队列中断开已取消的侍者节点。
private void unlinkCancelledWaiters() 
    Node t = firstWaiter;
    Node trail = null;
    while (t != null) 
        Node next = t.nextWaiter;
        if (t.waitStatus != Node.CONDITION) //状态CONDITION 的不要
            t.nextWaiter = null;
            if (trail == null)
                firstWaiter = next;
            else
                trail.nextWaiter = next;
            if (next == null)
                lastWaiter = trail;
        
        else
            trail = t;
        t = next;
    

就是说先将节点放进等待队列,然后释放竞争队列的,等条件达到要求、中断或者超时,线程等待完成后 重新获取锁

signal 唤醒操作

//唤醒操作  调用 doSignal方法
public final void signal() 
    if (!isHeldExclusively())//保证当前线程持有锁的状态下执行
        throw new IllegalMonitorStateException();
    Node first = firstWaiter;
    if (first != null)
        doSignal(first);

//唤醒一个等待节点 调用transferForSignal 方法
private void doSignal(Node first) 
    do //设置下一个等待节点
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        first.nextWaiter = null;
     while (!transferForSignal(first) &&
             (first = firstWaiter) != null);//如果放到 竞争队列失败 继续唤醒下一个节点

singall

//唤醒所有 调用 doSignalAll方法
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 //循环遍历 transferForSignal 方法唤醒节点
        Node next = first.nextWaiter;
        first.nextWaiter = null;
        transferForSignal(first);
        first = next;
     while (first != null);

transferForSignal原理

final boolean transferForSignal(Node node) 
	//CAS 将线程节点状态修改为0 
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
        return false;
	//enq 方法 将节点添加到AQS竞争队列
    Node p = enq(node);
    int ws = p.waitStatus;
    //如果前驱节点的状态 >0   CAS设置前驱节点状态SIGNAL 失败  unpark方法唤醒当前线程
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        LockSupport.unpark(node.thread);
    return true;

transferForSignal方法将节点转移到AQS的队列中,实际是调用了enq 方法。

以上是关于[JDK源码]J.U.C-AQS.ConditionObject的主要内容,如果未能解决你的问题,请参考以下文章

JDK1.8源码下载及idea2021导入jdk1.8源码

关于JDK源码:我想聊聊如何更高效地阅读

关于JDK源码:我想聊聊如何更高效地阅读

idea 导入 jdk源码 解决compile code 后阅读jdk 源码

关于JDK源码:我想聊聊如何更高效地阅读.md

怎样读jdk源码