Condition源码解读(二)

本章我们继续将Condition的最后一个方法signal方法,如果前面没有看过的可以点击LockSupport与Condition解析来看看Condition解读的前半部分。

signal方法:

        public final void signal() {
            if (!AbstractQueuedLongSynchronizer.this.isHeldExclusively()) {
                throw new IllegalMonitorStateException();
            } else {
                Node var1 = this.firstWaiter;
                if (var1 != null) {
                    this.doSignal(var1);
                }

            }
        }

signal方法的主要作用就是将线程从Condition队列中唤醒,前面已经讲述过在Condtion的子类ConditionObject内部通过链表来维护整个Condtion队列,并且含有两个属性firstWaiter和lastWaiter分别表示队列头和队列尾部,分析方法首先进行检查当前线程是否持有独占锁。目的是保证持有锁的线程才能调用signal方法来唤醒线程,通过判断之后开始从Condition队列中取出队首线程,随后开始调用doSignal方法来唤醒线程

        private void doSignal(Node var1) {
            do {
                if ((this.firstWaiter = var1.nextWaiter) == null) {
                    this.lastWaiter = null;
                }

                var1.nextWaiter = null;
            } while(!AbstractQueuedLongSynchronizer.this.transferForSignal(var1) && (var1 = this.firstWaiter) != null);

        }

在dosignal中首先将后面的node设置为链表头部,如果后续没有node则将尾链表置为null。

同时调用transferForSignal(first)尝试将节点转移到同步队列,如果转移失败(返回false)且队列还有节点(firstWaiter != null),继续处理下一个节点。

下面我们来看看transferForSignal方法是如何进行转移的。

 final boolean transferForSignal(Node var1) {
        if (!compareAndSetWaitStatus(var1, -2, 0)) {
            return false;
        } else {
            Node var2 = this.enq(var1);
            int var3 = var2.waitStatus;
            if (var3 > 0 || !compareAndSetWaitStatus(var2, var3, -1)) {
                LockSupport.unpark(var1.thread);
            }

            return true;
        }
    }

首先进行状态位的CAS设置,如果无法设置表明状态已经改变了直接返回false,表示无法入队。

之后进行入队enq操作(内部是一个循环不断的CAS操作保证能入队)入队完毕之后则查看当前节点状态如果还是阻塞状态则直接调用unpark来唤醒当前线程。

1. 先判断当前线程是否持有当前锁没有则抛出异常

2. 取出Condition队列中的一个首节点尝试入队和唤醒操作

3.失败则再次循环从队伍中取出节点

4.在尝试入队的方法总首先会判断状态值是否符合不符合则直接返回false,符合则会通过CAS循环入队操作,最后判断状态是否为阻塞,为阻塞则直接调用unpark方法进行唤醒操作。

至此Condtion的两个方法已经介绍完毕。

总结:

await方法:

Condition源码解读(二)_第1张图片

signal方法:

Condition源码解读(二)_第2张图片

设计精髓

  1. 双队列分离:条件队列(等待条件)与同步队列(竞争锁)分离

  2. 状态驱动waitStatus 精确控制节点生命周期

  3. 无锁算法:CAS 操作保证线程安全

  4. 协作式唤醒:前驱节点负责唤醒后继

  5. 资源继承:await() 返回时自动恢复原始锁状态

典型应用场景

  1. 生产者-消费者:不同条件控制队列空/满

  2. 线程池任务调度:工作线程等待任务到达

  3. 资源池管理:连接可用性通知

  4. 屏障实现:所有线程到达后同时释放

  5. 状态机转换:特定状态变更触发操作

你可能感兴趣的:(并发编程,java,开发语言)