【Java面试】Queue接口

news2024/11/20 14:39:14

文章目录

  • BlockingQueue中有哪些方法,为什么这样设计?
  • BlockingQueue是怎么实现的?

BlockingQueue中有哪些方法,为什么这样设计?

先看一眼结构,再看具体的分析
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
为了应对不同的业务场景,BlockingQueue 提供了4 组不同的方法用于插入、移除以及对队列中的元素进行检查。如果请求的操作不能得到立即执行的话,每组方法的表现是不同的。这些方法如下:
在这里插入图片描述
四组不同的行为方式含义如下:

  • 抛异常:如果操作无法立即执行,则抛一个异常;

  • 特定值:如果操作无法立即执行,则返回一个特定的值(一般是 true / false)。

  • 阻塞:如果操作无法立即执行,则该方法调用将会发生阻塞,直到能够执行;

  • 超时:如果操作无法立即执行,则该方法调用将会发生阻塞,直到能够执行。但等待时间不会超过给定值,并返回一个特定值以告知该操作是否成功(典型的是true / false)。

BlockingQueue是怎么实现的?

BlockingQueue是一个接口,它的实现类有ArrayBlockingQueue、DelayQueue、 LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue等。它们的区别主要体现在存储结构上或对元素操作上的不同,但是对于put与take操作的原理是类似的。下面以ArrayBlockingQueue为例,来说明BlockingQueue的实现原理。

首先看一下ArrayBlockingQueue的构造函数,它初始化了put和take函数中用到的关键成员变量,这两个变量的类型分别是ReentrantLock和Condition。ReentrantLock是AbstractQueuedSynchronizer(AQS)的子类,它的newCondition函数返回的Condition实例,是定义在AQS类内部的ConditionObject类,该类可以直接调用AQS相关的函数。

public ArrayBlockingQueue(int capacity, boolean fair) {    
  if (capacity <= 0)   
       throw new IllegalArgumentException();     
        this.items = new Object[capacity];     
         lock = new ReentrantLock(fair);      
         notEmpty = lock.newCondition();      
         notFull = lock.newCondition();  
         }

put函数会在队列末尾添加元素,如果队列已经满了,无法添加元素的话,就一直阻塞等待到可以加入为止。函数的源码如下所示。我们会发现put函数使用了wait/notify的机制。与一般生产者-消费者的实现方式不同,同步队列使用ReentrantLock和Condition相结合的机制,即先获得锁,再等待,而不是synchronized和wait的机制。

public void put(E e) throws InterruptedException {     
 checkNotNull(e);    
   final ReentrantLock lock = this.lock;     
    lock.lockInterruptibly();     
     try {       
        while (count == items.length)       
               notFull.await();         
                enqueue(e);      
                } finally {      
                    lock.unlock();      
                    }  }

再来看一下消费者调用的take函数,take函数在队列为空时会被阻塞,一直到阻塞队列加入了新的元素。

public E take() throws InterruptedException {  
    final ReentrantLock lock = this.lock;     
     lock.lockInterruptibly();  
         try {    
               while (count == 0)      
                       notEmpty.await(); 
                                return dequeue();   
                                   } finally {
                                             lock.unlock();  
                                                 }  }

await操作:

我们发现ArrayBlockingQueue并没有使用Object.wait,而是使用的Condition.await,这是为什么呢?Condition对象可以提供和Object的wait和notify一样的行为,但是后者必须先获取synchronized这个内置的monitor锁才能调用,而Condition则必须先获取ReentrantLock。这两种方式在阻塞等待时都会将相应的锁释放掉,但是Condition的等待可以中断,这是二者唯一的区别。

我们先来看一下Condition的await函数,await函数的流程大致如下图所示。await函数主要有三个步骤,一是调用addConditionWaiter函数,在condition wait queue队列中添加一个节点,代表当前线程在等待一个消息。然后调用fullyRelease函数,将持有的锁释放掉,调用的是AQS的函数。最后一直调用isOnSyncQueue函数判断节点是否被转移到sync queue队列上,也就是AQS中等待获取锁的队列。如果没有,则进入阻塞状态,如果已经在队列上,则调用acquireQueued函数重新获取锁。
在这里插入图片描述

signal操作:

signal函数将condition wait queue队列中队首的线程节点转移等待获取锁的sync queue队列中。这样的话,await函数中调用isOnSyncQueue函数就会返回true,导致await函数进入最后一步重新获取锁的状态。

我们这里来详细解析一下condition wait queue和sync queue两个队列的设计原理。condition wait queue是等待消息的队列,因为阻塞队列为空而进入阻塞状态的take函数操作就是在等待阻塞队列不为空的消息。而sync queue队列则是等待获取锁的队列,take函数获得了消息,就可以运行了,但是它还必须等待获取锁之后才能真正进行运行状态。

signal函数其实就做了一件事情,就是不断尝试调用transferForSignal函数,将condition wait queue队首的一个节点转移到sync queue队列中,直到转移成功。因为一次转移成功,就代表这个消息被成功通知到了等待消息的节点。

signal函数的示意图如下所示。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/162957.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

拉伯证券|业绩猛增超13倍,主力连续抢筹,这只股收获4连板

成绩陡增股获主力接连抢筹 春节日益接近&#xff0c;A股成交活跃度有所下滑&#xff0c;不过有一些股票节前继续取得主力喜爱。证券时报•数据宝核算&#xff0c;到1月12日收盘&#xff0c;沪深两市共54只个股接连5日或5日以上主力资金净流入。 主力资金净流入继续周期最长的是…

人工智能学习07--pytorch03--tensorboard(下载tensorboard、opencv)

transform 主要是对input图像进行变换&#xff08;统一尺寸、对图像中的数据进行类的转换&#xff09; TensorBoard很有用 如&#xff1a;通过loss的变化过程&#xff0c;来看loss的变化是否复合预想。也可以通过loss来选择模型。 TensorBoard&#xff0c;虽然他是TensorFlo…

排序综合(C++版)

目录 排序综合 一、问题描述 二、运行环境说明 三、代码段 四、效果展示 排序综合 备注&#xff1a;大二&#xff08;上&#xff09;数据结构课程设计B题 一、问题描述 给定N…

Python asyncio异步编程简单实现

今天继续给大家介绍Python相关知识&#xff0c;本文主要内容是Python asyncio异步编程简单实现。 一、asyncio事件循环简介 asyncio引入了事件循环的概念。事件循环是一个死循环&#xff0c;还循环会检测并执行某些代码。在Python中&#xff0c;引入了asyncio模块后&#xff…

动态内存管理:学习笔记9

目录 一.前言 二.动态内存函数 1.malloc和free 2.calloc函数 3. realloc函数(动态内存空间调整函数) 情形一&#xff1a;扩容时&#xff0c;原内存地址处可以容纳调整后的动态内存 情形二&#xff1a;扩容时&#xff0c;原内存地址无法容纳调整后的动态内存 三.C/C程序…

MATLAB实现费诺编码的计算与分析

一、实验目的 1、理解霍费诺编码的原理。 2、掌握费诺编码的方法和步骤。 3、熟悉费诺编码的效率。 4、本实验用Matlab语言编程实现费诺&#xff08;Fano&#xff09;编码。 二、实验环境 windows XP&#xff0c;MATLAB 7 三、实验原理 费诺编码算法如下&#xff1a;在信源…

构建前端项目

1.使用vite构建vue项目 vite构建vue项目&#xff0c;输入以下命令&#xff1a; npm init vitelatest接着按照提示的命令选择项目的名称、框架、语言。接着项目就构建完成了。 接着将构建好的项目&#xff1a;vite-demo拖入vsCode里面&#xff0c;在package.json中可以看到项…

redis基础命令使用

目录 Redis redis存储结构&#xff08;KV&#xff09; String string类型介绍 string类型数据的基础操作 string类型数据的扩展操作 List list类型介绍 list类型数据基本操作 list类型数据扩展操作 hash hash类型介绍 hash类型数据的基本操作 hash类型数据扩展操…

傅里叶变换

傅里叶变换 傅里叶变换常用的三个函数 函数一: numpy.fft.fft2: 复数数组 函数二: numpy.fft.fftshift: 将零频率分量移动到频谱中心 函数三: 20*np.log(np.abs(fshift)) 设置频谱的范围 import cv2 import numpy as np import matplotlib.pyplot as pltdef test_1():img cv2…

再说多线程(三)——Mutex类

1.引子在前面2节&#xff0c;我们已经讨论了Lock语句和Monitor类&#xff0c;Locks 和 Monitors 确保 InProcess 线程的线程安全&#xff0c;即由应用程序本身生成的线程&#xff0c;即内部线程。但是&#xff0c;如果线程来自 OutProcess&#xff0c;即来自外部应用程序&#…

Java 诊断利器 Arthas monitor/watch/trace命令

一、监控相关命令介绍 二、监控相关命令 2.1、运行Demo 2.2、monitor 命令 2.2.1、方法监控 2.3、watch 命令 &#xff08;重要&#xff09; 2.3.1、观察函数调用返回时的参数、this 对象和返回值 2.3.2、查看函数调用的入参和返回值 2.3.3、深度遍历 x 说明 2.3.4、查…

检验仪器控制怎么停止的

之前介绍仪器控制启动是按维护的调用M和仪器ID组串直接j启动进程&#xff0c;进程在调用Start启动TCP。 组装执行M串用j启动进程 启动TCP通道&#xff0c;成功之后就到f的死循环了 死循环这里容易有个误解&#xff0c;以为Stop是停止仪器接口的。其实这个Stop是判断要不要…

一灯大师,基于imx6ull点亮LED灯

一.imx6ull GPIO原理1. STM32 GPIO回顾我们一般拿到一款全新的芯片&#xff0c;第一个要做的事情的就是驱动其 GPIO&#xff0c;控制其 GPIO 输出高低电平&#xff0c;我们学习 I.MX6U 也一样的&#xff0c;先来学习一下 I.MX6U 的 GPIO。在学习 I.MX6U的 GPIO 之前&#xff0c…

Spark WordCount 案例

文章目录Spark WordCount 案例1、程序连接 Spark2、WordCount 案例示例3、复杂版 WordCount4、Spark 框架WordcountSpark WordCount 案例 1、程序连接 Spark 首先这个Scala spark程序和spark的链接&#xff0c;跟sql编程类似。首先new 一个新的val context SparkContext()对…

谷粒商城-高级篇-Day10-ElasticSearch

初步检索 1、_cat GET /_cat/nodes:查看所有节点 GET/_cat/health:查看es健康状况 GET/_cat/master:查看主节点 GET/_cat/indices:查看所有索引–相当于查询所有数据库 2、索引一个文档 put&#xff1a;http://192.168.205.128:9200/customer/external/1 {"name&qu…

Qt之加载百度离线地图(WebKit和WebEngine)

最近翻看进年前写了一篇关于百度离线地图的博客:Qt加载百度离线地图,发现存在很多问题,比如不能加载折线等图形覆盖物;只支持QtWebKit,不支持QtWebEngine。 之前做项目需要在百度离线地图上绘制Mesh拓扑图,必须添加折线覆盖物,使用的是百度离线地图API V2.1,满足需求。…

Java注解详解

什么是注解 ​ 用一个词就可以描述注解&#xff0c;那就是元数据&#xff0c;即一种描述数据的数据。所以&#xff0c;可以说注解就是源代码的元数据 元注解 JDK1.5之后内部提供的注解&#xff1a; Deprecated 意思是“废弃的&#xff0c;过时的”Override 意思是“重写、覆…

算法训练营 day18 二叉树 找树左下角的值 路径总和 从中序与后序遍历构建二叉树

算法训练营 day18 二叉树 找树左下角的值 路径总和 从中序与后序遍历构建二叉树 找树的左下角 513. 找树左下角的值 - 力扣&#xff08;LeetCode&#xff09; 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节…

Java --- JUC之原子类

目录​​​​​​​ 一、基本类型原子类 二、数组类型原子类 三、引用类型原子类 四、对象的属性修改类型原子类 五、原子操作增强类 5.1、高性能热点商品应用 5.2、LongAdder架构图 5.3、源码分析 一、基本类型原子类 public class AtomicTest1 {public static final…

canvas:基础知识【直线和矩形】

canvas&#xff0c;就是画布&#xff0c;是HTML5和核心技术之一&#xff0c;结合JavaScript&#xff0c;可以绘制各种各样的图形&#xff0c;比如矩形、曲线、圆形等等。另外&#xff0c;canvas可以绘制图表、动画效果、游戏开发。 基本图形汇中有直线和曲线。常见的直线图形是…