Java并发系列 | AbstractQueuedSynchronizer源码分析之条件队列
发布日期:2021-05-19 16:45:02 浏览次数:13 分类:精选文章

本文共 3238 字,大约阅读时间需要 10 分钟。

AbstractQueuedSynchronizer(简称AQS)是Java并发编程中非常重要的同步机制,它为复杂的多线程应用提供了基础的后勤支持。作为其他同步类(如ReentrantLock)的基石,AQS通过两种队列——同步队列和条件队列——来协调线程的进入和中断过程。

AQS 的核心逻辑

AQS 的主要目标是支持线程之间的竞争性和协调性。当一个线程试图获取某个锁时,如果锁被其他线程占有,请求线程就会进入AQS的条件等待机制。这一机制通过条件队列(Condition Queue)来管理线程的中断状态。

条件队列:线程的等待室

条件队列(Condition Queue)类似于一个快乐的面板,上面记录了线程因为某些条件而被暂停的状态。在AQS中,条件队列主要有以下功能:

  • 接收需要等待的线程
  • 醉酒请等等...

当线程因为某种条件而无法继续执行时,它会将自己从同步队列中移出,并进入条件队列等待。这时,线程进入一种潜在状态,等待某些特定条件被满足,例如另一个线程释放锁并完成某项工作。

条件队列中的每个记录都与一个线程相关,线程在接收到信号(通过signal方法调用)后会被唤醒并重新加入同步队列等待锁。

signal 方法: 唤醒线程

signal方法是AQS中非常重要的一招,它负责唤醒条件队列中的线程。具体来说,signal方法执行以下操作:

  • 检查当前线程是否持有锁,如果没有,则抛出异常。
  • 进入条件队列,找到第一个等待的线程(head)。
  • 调用doSignal方法,将该线程从条件队列中移出,并重新插入到同步队列中等待。
  • 这意味着,只要一个线程进入条件队列,它都会在signal方法被唤醒。而signalAll方法则会继续处理整个条件队列中的所有线程,将其全部唤醒。

    await 方法: 线程的等待状态

    await方法是线程在遇到阻塞时使用的核心功能。当线程发现自己无法继续获取锁时,就会调用await方法,进入条件队列等待。具体来说,await方法的实现分为以下几个步骤:

  • 创建条件等待节点:将当前线程包装成一个节点,并添加到条件队列尾部。
  • 释放锁:由于线程进入条件队列等待,必须先完全释放锁。
  • 进入等待状态:在线程中挂起,等待signal方法的唤醒。
  • 这一过程确保了线程在离开锁后不会立即干扰其他线程,从而保持了锁的互斥性。

    条件队列的处理逻辑

    在详细解读源码之前,我们需要理解条件队列的处理逻辑。首先要了解的是,如何将条件队列中的线程唤醒,以及哪些情况下会触发唤醒。通常,唤醒的条件包括:

  • 条件队列的前驱节点被取消等待。
  • 条件队列的前驱节点的状态被改为SIGNALFAIL。
  • 前驱节点释放锁后主动唤醒。
  • 通过这三种情况,AQS确保了线程等待的效率和准确性。

    源码分析

    Response-sensitive Condition await()

    public final void await() throws InterruptedException { if (Thread.interrupted()) { throw new InterruptedException(); } Node node = addConditionWaiter(); int savedState = fullyRelease(node); boolean interruptMode = 0; while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) { break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) { interruptMode = REINTERRUPT; } if (node.nextWaiter != null) { unlinkCancelledWaiters(); } if (interruptMode != 0) { reportInterruptAfterWait(interruptMode); } } // ... 后续操作 }

    No-interruptible Condition await()

    public final void awaitUninterruptibly() { Node node = addConditionWaiter(); int savedState = fullyRelease(node); while (!isOnSyncQueue(node)) { LockSupport.park(this); if (Thread.interrupted()) { boolean interrupted = true; } } if (acquireQueued(node, savedState) || interrupted) { selfInterrupt(); } }

    Timed Condition await()

    public final long awaitNanos(long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) { throw new InterruptedException(); } Node node = addConditionWaiter(); int savedState = fullyRelease(node); long lastTime = System.nanoTime(); long nanosRemaining = nanosTimeout; while (!isOnSyncQueue(node)) { if (nanosRemaining <= 0) { transferAfterCancelledWait(node); break; } LockSupport.parkNanos(this, nanosRemaining); nanosRemaining -= System.nanoTime() - lastTime; lastTime = System.nanoTime(); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) { break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) { interruptMode = REINTERRUPT; } if (node.nextWaiter != null) { unlinkCancelledWaiters(); } if (interruptMode != 0) { reportInterruptAfterWait(interruptMode); } } return nanosRemaining - (System.nanoTime() - lastTime); }

    总结

    通过以上分析可以看出,AbstractQueuedSynchronizer为Java 的 Locking机制提供了一种灵活且高效的条件等待方式。它通过同步队列和条件队列,协调多线程环境中的资源竞争和等待状态,这使得复杂的同步操作更加高效和可靠。

    AQS 是现代Java 式的基石,它不仅用于ReentrantLock,还为其他同步机制如Semaphore、ConcurrentQueue等提供了强大的后勤支持。如果你对这个话题有进一步的兴趣,可以深入探索它的具体实现细节。

    上一篇:redis,学会这8点
    下一篇:Java8之stream

    发表评论

    最新留言

    哈哈,博客排版真的漂亮呢~
    [***.90.31.176]2025年05月04日 21时35分30秒

    关于作者

        喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
    -- 愿君每日到此一游!

    推荐文章

    Kubernetes学习总结(10)—— 何为云原生,与 kubernetes 是什么关系 2025-04-03
    Kubernetes学习总结(11)—— Kubernetes Pod 到底是什么? 2025-04-03
    Kubernetes学习总结(12)—— 学习 kubernetes 的10个技巧或建议 2025-04-03
    Kubernetes学习总结(13)—— Kubernetes 各个组件的概念 2025-04-03
    Kubernetes学习总结(14)—— Kubernetes 实用命令总结 2025-04-03
    Kubernetes学习总结(15)—— Kubernetes 实战之部署 Mysql 集群 2025-04-03
    Kubernetes学习总结(16)—— Kubernetes 实战之部署 Redis 集群 2025-04-03
    Kubernetes学习总结(17)—— Kubernetes 快速入门需要掌握的知识点总结 2025-04-03
    Kubernetes学习总结(18)—— Kubernetes 容器网络 2025-04-03
    Kubernetes学习总结(1)——Kubernetes入门简介 2025-04-03
    Kubernetes学习总结(2)——Kubernetes设计架构 2025-04-03
    Kubernetes学习总结(3)——一年时间打造全球最大规模之一的Kubernetes集群,蚂蚁金服怎么做到的? 2025-04-03
    Kubernetes学习总结(4)——Kubernetes v1.20 重磅发布 | 新版本核心主题 & 主要变化解读 2025-04-03
    Kubernetes学习总结(5)——Kubernetes 常见面试题汇总 2025-04-03
    Kubernetes学习总结(6)——Kubernetes 7周年:它为什么如此受欢迎? 2025-04-03
    Kubernetes学习总结(7)——学习 Kubernetes 的 Pod 2025-04-03
    Kubernetes学习总结(8)—— Kubernetes Pod 资源管理 和 Pod 服务质量 2025-04-03
    Kubernetes学习总结(9)—— 基础架构的未来是 K8s,那么 K8s 的未来在何方? 2025-04-03
    kubernetes实战(十三):k8s使用helm持久化部署harbor集成openLDAP登录 2025-04-03
    Kubernetes实战(一)-Kubernetes集群搭建 2025-04-03