概要

AQS维护了一个同步队列

Condition是JUC的一个接口,AQS的ConditionObject实现了这个接口,维护了一个等待队列(等待signal信号的队列)

线程调用reentrantLock.lock()时,线程被加入到AQS同步队列中;

线程A调用condition.await()方法时,线程A从AQS同步队列中被移除,被加入到Condition等待队列,等待signal信号

线程B调用signal()方法,Condition等待队列中有一个节点A,把它取出来(A)加入到AQS同步队列中。这时候线程A并没有被唤醒(signal可以指定唤醒哪个condition)

只有发送singal信号的线程调用reentrantLock.unLock()后,因为它(线程A)已经被加入到AQS同步队列并且成为同步队列头结点,所以线程才会被唤醒。

之前对AbstractQueuedSynchronizer(AQS)同步队列与Condition等待队列的功能一直不是很清晰,没太清楚地区分开二者的区别和联系,最近研究了一下分享出来。

例子分析参见另一篇文章:【JUC】Condition和生产者消费者模型  https://www.cnblogs.com/twoheads/p/9591874.html

1.同步队列和等待队列简述

说明:AbstractQueuedSynchronizer类底层的数据结构是使用链表,是队列的一种实现,故也可看成是队列,其中Sync queue,即同步队列,是双向链表,包括head结点和tail结点,head结点主要用作后续的调度。而Condition queue即等待队列不是必须的,其是一个单向链表,只有当使用Condition时,才会存在此单向链表。并且可能会有多个Condition queue。Condition的具体实现类是AQS的内部类ConditionObject

我们知道AQS自己维护的队列是当前等待资源的队列,当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成为一个节点并将其加入同步队列,同时会阻塞当前线程,当同步状态释放时,会把首节点中的线程唤醒,使其再次尝试获取同步状态。

而Condition自己也维护了一个等待队列(等待signal信号的队列),两个队列的作用是不同,事实上,每个线程也仅仅会同时存在以上两个队列中的一个

每个Condition维护着一个队列,该队列的作用是维护一个等待signal信号的队列。

    //AQS中的Node属性
static final class Node {
...
volatile int waitStatus;//等待状态
volatile Node prev;//前驱节点
volatile Node next;//后驱节点
volatile Thread thread;//获取同步状态的线程,当前执行线程
Node nextWaiter;//等待队列中的后继节点
...
}

从上述Node结构可以看出,其实同步队列和等待队列使用的是同一个Node类型AbstractQueuedSynchronizer.Node。

2.同步队列和等待队列区别与协同机制

下面我们举一个具体的例子来说明同步队列和等待队列之间的区别与协同工作:

  1. 同步队列的初始状态为下图,同步队列中包含线程A(节点A)和线程B(节点B),线程调用reentrantLock.lock()时,线程被加入到AQS同步队列中

  2. 线程A(节点A)调用condition.await()方法时,线程A(节点A)从AQS同步队列中被移除,对应操作是锁的释放; 线程A(节点A)接着被加入到Condition等待队列,因为线程需要signal信号。
  3. 线程B(节点B)由于线程A(节点A)释放锁被唤醒,判断成为同步队列头结点且同步状态为0可以获取锁;线程B(节点B)获取锁。

  4. 线程B(节点B)调用signal()方法,Condition等待队列中有一个节点A,把它取出来(A)加入到AQS同步队列中。这时候线程A(节点A)并没有被唤醒。

  5. 线程B(节点B)signal方法执行完毕,并调用reentrantLock.unLock()方法释放锁。线程A(节点A)成为AQS首节点并且同步状态可获取,线程A(节点A)被唤醒,继续执行。
  6. AQS从头到尾顺序唤醒线程,直到等待队列中的线程被执行完毕结束。

只有发送singal信号的线程调用reentrantLock.unLock()后,因为它已经被加入到AQS同步队列并且成为同步队列头结点,所以线程才会被唤醒。

转:

https://blog.csdn.net/tb3039450/article/details/69056169

http://ifeve.com/understand-condition/

AbstractQueuedSynchronizer同步队列与Condition等待队列协同机制的更多相关文章

  1. Java并发包源码学习系列:CLH同步队列及同步资源获取与释放

    目录 本篇学习目标 CLH队列的结构 资源获取 入队Node addWaiter(Node mode) 不断尝试Node enq(final Node node) boolean acquireQue ...

  2. 学习JUC源码(3)——Condition等待队列(源码分析结合图文理解)

    前言 在Java多线程中的wait/notify通信模式结尾就已经介绍过,Java线程之间有两种种等待/通知模式,在那篇博文中是利用Object监视器的方法(wait(),notify().notif ...

  3. Java并发编程(您不知道的线程池操作), 最受欢迎的 8 位 Java 大师,Java并发包中的同步队列SynchronousQueue实现原理

    Java_并发编程培训 java并发程序设计教程 JUC Exchanger 一.概述 Exchanger 可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchan ...

  4. Java并发编程3-抽象同步队列AQS详解

    AQS是AtractQueuedSynchronizer(队列同步器)的简写,是用来构建锁或其他同步组件的基础框架.主要通过一个int类型的state来表示同步状态,内部有一个FIFO的同步队列来实现 ...

  5. Java并发包之同步队列SynchronousQueue理解

    1 简介 SynchronousQueue是这样一种阻塞队列,其中每个put必须等待一个take,反之亦然.同步队列没有任何内部容量,甚至连一个队列的容量都没有.不能在同步队列上进行peek,因为仅在 ...

  6. 【转载】阻塞队列之三:SynchronousQueue同步队列 阻塞算法的3种实现

    一.SynchronousQueue简介 Java 6的并发编程包中的SynchronousQueue是一个没有数据缓冲的BlockingQueue,生产者线程对其的插入操作put必须等待消费者的移除 ...

  7. 【死磕Java并发】-----J.U.C之AQS:CLH同步队列

    此篇博客全部源代码均来自JDK 1.8 在上篇博客[死磕Java并发]-–J.U.C之AQS:AQS简单介绍中提到了AQS内部维护着一个FIFO队列,该队列就是CLH同步队列. CLH同步队列是一个F ...

  8. 阻塞队列之三:SynchronousQueue同步队列 阻塞算法的3种实现

    一.SynchronousQueue简介 Java 6的并发编程包中的SynchronousQueue是一个没有数据缓冲的BlockingQueue,生产者线程对其的插入操作put必须等待消费者的移除 ...

  9. CLH同步队列

    原文链接:https://blog.csdn.net/chenssy/article/details/60781148 AQS内部维护着一个FIFO队列,该队列就是CLH同步队列. CLH同步队列是一 ...

随机推荐

  1. shell脚本--分支、条件判断

    在看选择判断结构之前,请务必先看一下数值比较与文件测试 if....else... #!/bin/bash #文件名:test.sh score=66 # //格式一 if [ $score -lt ...

  2. AWK学习一例

    awk 'BEGIN { for (i = 1; i <= 7; i++) print int(101 * rand()) }'

  3. ThinkPad E470 win10,重装win10专业版后无声音

    解决办法: 1.官网下载笔记本对应的声卡驱动并安装 2.下载热键驱动并安装 3.重启笔记本即可 参考:https://blog.csdn.net/u012369373/article/details/ ...

  4. DTW的原理及matlab实现(转载+整理)

    在大部分的学科中,时间序列是数据的一种常见表示形式.对于时间序列处理来说,一个普遍的任务就是比较两个序列的相似性. 在时间序列中,需要比较相似性的两段时间序列的长度可能并不相等,在语音识别领域表现为不 ...

  5. python 授权

    1.“包装”意思是一个已经存在的对象进行包装,不管他是数据类型还是一段代码,可以是对一个已经存在的对象增加新的,删除不要的或者修改其他已经存在的功能 2.包装 包括定义一个类,他的实例拥有标准类型的核 ...

  6. nginx-日志统计

    #!/bin/bash fd=/tmp/log# pv 点击量echo "###################点击量 --$pv-- #########################&q ...

  7. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  8. Hdoj 1009.FatMouse' Trade 题解

    Problem Description FatMouse prepared M pounds of cat food, ready to trade with the cats guarding th ...

  9. 【转】安全加密(二):BLE安全攻击反制措施

    本文导读 近年来出现了越来越多的低功耗蓝牙应用,即BLE(Bluetooth Low Energy),比如说智能手环.防丢器等,对蓝牙的安全要求也越来越高.这篇文章将深入浅出说明BLE4.0~4.2中 ...

  10. 洛谷 P3155 [CQOI2009]叶子的染色 解题报告

    P3155 [CQOI2009]叶子的染色 题目描述 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方案应该保证根结点到 ...