并发容器介绍(二)

并发容器介绍(二)

文章目录

  • 并发容器介绍(二)
    • BlockingQueue
      • BlockingQueue 简介
      • ArrayBlockingQueue
      • LinkedBlockingQueue
      • PriorityBlockingQueue
    • ConcurrentSkipListMap

文章来自Java Guide 用于学习如有侵权,立即删除

BlockingQueue

BlockingQueue 简介

上面我们己经提到了 ConcurrentLinkedQueue 作为高性能的非阻塞队列。下面我们要讲到的是阻塞队列——BlockingQueue。阻塞队列(BlockingQueue)被广泛使用在“生产者-消费者”问题中,其原因是 BlockingQueue 提供了可阻塞的插入和移除的方法。当队列容器已满,生产者线程会被阻塞,直到队列未满;当队列容器为空时,消费者线程会被阻塞,直至队列非空时为止。

BlockingQueue 是一个接口,继承自 Queue,所以其实现类也可以作为 Queue 的实现来使用,而 Queue 又继承自 Collection 接口。下面是 BlockingQueue 的相关实现类:

BlockingQueue 的实现类

下面主要介绍一下 3 个常见的 BlockingQueue 的实现类:ArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueue

ArrayBlockingQueue

ArrayBlockingQueueBlockingQueue 接口的有界队列实现类,底层采用数组来实现。

public class ArrayBlockingQueue<E>
extends AbstractQueue<E>
implements BlockingQueue<E>, Serializable{}

ArrayBlockingQueue 一旦创建,容量不能改变。其并发控制采用可重入锁 ReentrantLock ,不管是插入操作还是读取操作,都需要获取到锁才能进行操作。当队列容量满时,尝试将元素放入队列将导致操作阻塞;尝试从一个空队列中取一个元素也会同样阻塞。

ArrayBlockingQueue 默认情况下不能保证线程访问队列的公平性,所谓公平性是指严格按照线程等待的绝对时间顺序,即最先等待的线程能够最先访问到 ArrayBlockingQueue。而非公平性则是指访问 ArrayBlockingQueue 的顺序不是遵守严格的时间顺序,有可能存在,当 ArrayBlockingQueue 可以被访问时,长时间阻塞的线程依然无法访问到 ArrayBlockingQueue。如果保证公平性,通常会降低吞吐量。如果需要获得公平性的 ArrayBlockingQueue,可采用如下代码:

private static ArrayBlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(10,true);

LinkedBlockingQueue

LinkedBlockingQueue 底层基于单向链表实现的阻塞队列,可以当做无界队列也可以当做有界队列来使用,同样满足 FIFO 的特性,与 ArrayBlockingQueue 相比起来具有更高的吞吐量,为了防止 LinkedBlockingQueue 容量迅速增,损耗大量内存。通常在创建 LinkedBlockingQueue 对象时,会指定其大小,如果未指定,容量等于 Integer.MAX_VALUE

相关构造方法:

    /**
     *某种意义上的无界队列
     * Creates a {@code LinkedBlockingQueue} with a capacity of
     * {@link Integer#MAX_VALUE}.
     */
    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

    /**
     *有界队列
     * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
     *
     * @param capacity the capacity of this queue
     * @throws IllegalArgumentException if {@code capacity} is not greater
     *         than zero
     */
    public LinkedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        last = head = new Node<E>(null);
    }

PriorityBlockingQueue

PriorityBlockingQueue 是一个支持优先级的无界阻塞队列。默认情况下元素采用自然顺序进行排序,也可以通过自定义类实现 compareTo() 方法来指定元素排序规则,或者初始化时通过构造器参数 Comparator 来指定排序规则。

PriorityBlockingQueue 并发控制采用的是可重入锁 ReentrantLock,队列为无界队列(ArrayBlockingQueue 是有界队列,LinkedBlockingQueue 也可以通过在构造函数中传入 capacity 指定队列最大的容量,但是 PriorityBlockingQueue 只能指定初始的队列大小,后面插入元素的时候,如果空间不够的话会自动扩容)。

简单地说,它就是 PriorityQueue 的线程安全版本。不可以插入 null 值,同时,插入队列的对象必须是可比较大小的(comparable),否则报 ClassCastException 异常。它的插入操作 put 方法不会 block,因为它是无界队列(take 方法在队列为空的时候会阻塞)。

推荐文章: 《解读 Java 并发队列 BlockingQueue》

ConcurrentSkipListMap

下面这部分内容参考了极客时间专栏《数据结构与算法之美》以及《实战 Java 高并发程序设计》。

为了引出 ConcurrentSkipListMap,先带着大家简单理解一下跳表。

对于一个单链表,即使链表是有序的,如果我们想要在其中查找某个数据,也只能从头到尾遍历链表,这样效率自然就会很低,跳表就不一样了。跳表是一种可以用来快速查找的数据结构,有点类似于平衡树。它们都可以对元素进行快速的查找。但一个重要的区别是:对平衡树的插入和删除往往很可能导致平衡树进行一次全局的调整。而对跳表的插入和删除只需要对整个数据结构的局部进行操作即可。这样带来的好处是:在高并发的情况下,你会需要一个全局锁来保证整个平衡树的线程安全。而对于跳表,你只需要部分锁即可。这样,在高并发环境下,你就可以拥有更好的性能。而就查询的性能而言,跳表的时间复杂度也是 O(logn) 所以在并发数据结构中,JDK 使用跳表来实现一个 Map。

跳表的本质是同时维护了多个链表,并且链表是分层的,

2级索引跳表

最低层的链表维护了跳表内所有的元素,每上面一层链表都是下面一层的子集。

跳表内的所有链表的元素都是排序的。查找时,可以从顶级链表开始找。一旦发现被查找的元素大于当前链表中的取值,就会转入下一层链表继续找。这也就是说在查找过程中,搜索是跳跃式的。如上图所示,在跳表中查找元素 18。

在跳表中查找元素18

查找 18 的时候原来需要遍历 18 次,现在只需要 7 次即可。针对链表长度比较大的时候,构建索引查找效率的提升就会非常明显。

从上面很容易看出,跳表是一种利用空间换时间的算法。

使用跳表实现 Map 和使用哈希算法实现 Map 的另外一个不同之处是:哈希并不会保存元素的顺序,而跳表内所有的元素都是排序的。因此在对跳表进行遍历时,你会得到一个有序的结果。所以,如果你的应用需要有序性,那么跳表就是你不二的选择。JDK 中实现这一数据结构的类是 ConcurrentSkipListMap

大家好,我是xwhking,一名技术爱好者,目前正在全力学习 Java,前端也会一点,如果你有任何疑问请你评论,或者可以加我QQ(2837468248)说明来意!希望能够与你共同进步

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大模型字典中加入特殊字符

大模型字典中加入特殊字符 在微调大模型的时候会遇到添加特殊字符&#xff0c;例如在微调多轮的数据的时候需要加入人和机器等特殊标识字符&#xff0c;如用这个特殊字符表示人&#xff0c;用这个特殊字符表示机器&#xff0c;从而实现了人机对话。一般在大模型中base字典中不…

二次供水无人值守解决方案

二次供水无人值守解决方案 二次供水系统存在一定的管理难题和技术瓶颈&#xff0c;如设备老化、维护不及时导致的水质安全隐患&#xff0c;以及如何实现高效运行和智能化管理等问题。在一些地区&#xff0c;特别是老旧小区或农村地区&#xff0c;二次供水设施建设和改造滞后&a…

【go语言开发】redis简单使用

本文主要介绍redis安装和使用。首先安装redis依赖库&#xff0c;这里是v8版本&#xff1b;然后连接redis&#xff0c;完成基本配置&#xff1b;最后测试封装的工具类 文章目录 安装redis依赖库连接redis和配置工具类封装代码测试 欢迎大家访问个人博客网址&#xff1a;https://…

初学Vue——Vue路由

0 什么是Vue路由 类似于Html中的超链接(<a>)一样&#xff0c;可以跳转页面的一种方式。 前端路由&#xff1a;URL中hash(#号之后的内容)与组件之间的对应关系&#xff0c;如下图&#xff1a; 当我们点击左侧导航栏时&#xff0c;浏览器的地址栏会发生变化&#xff0c;路…

hutool,真香!

大家好&#xff0c;我是苏三&#xff0c;又跟大家见面了。 前言 今天给大家介绍一个能够帮助大家提升开发效率的开源工具包&#xff1a;hutool。 Hutool是一个小而全的Java工具类库&#xff0c;通过静态方法封装&#xff0c;降低相关API的学习成本&#xff0c;提高工作效率&…

IOT的发展历程及其优势——青创智通

工业互联网-物联网-设备改造-IOT-青创智通 ​随着科技的不断发展&#xff0c;物联网&#xff08;IoT&#xff09;已经逐渐成为了我们生活中不可或缺的一部分。IoT是指通过互联网将各种物理设备连接起来&#xff0c;实现设备之间的数据交换和智能化控制。IoT的发展不仅改变了我们…

四管齐下 共建发展 | 七巧低代码助力零售行业打造一体化协同解决方案

行业背景 随着互联网和移动技术的普及&#xff0c;零售行业的销售渠道日趋多元化和融合化&#xff0c;传统线下渠道和新兴线上渠道相互竞争和协作&#xff0c;形成了新零售和全渠道的格局。快消品新零售模式下&#xff0c;企业需要通过数字化和智能化的手段&#xff0c;实现对…

Flask python 开发篇:项目布局

一、背景简介 Flask应用程序可以像单个文件一样简单。就像上一篇简单实现一个接口一样&#xff0c;所有的东西都在一个python文件内&#xff1b; 然而&#xff0c;当项目越来越大的时候&#xff0c;把所有代码放在单个文件中就有点不堪重负了。 Python 项目使用 包 来管理代码…

携手亚信安慧AntDB,在数智化浪潮中乘风破浪

随着大数据时代的到来&#xff0c;对数据库的需求愈发强烈。在这一背景下&#xff0c;国产数据库逐渐崭露头角&#xff0c;亚信安慧AntDB作为重要的代表产品之一正积极参与到激烈的市场竞争中。亚信安慧AntDB不仅追求技术的革新和突破&#xff0c;同时也致力于满足用户日益增长…

【Python】conda 命令报错解决:Example: conda --no-plugins install <package>

目录 报错效果&#xff1a;解决方法总结 欢迎关注 『Python』 系列&#xff0c;持续更新中 欢迎关注 『Python』 系列&#xff0c;持续更新中 报错效果&#xff1a; An unexpected error has occurred. Conda has prepared the above report. If you suspect this error is bei…

OD_2024_C卷_200分_9、园区参观路径【JAVA】【动态规划】

package odjava;import java.util.Scanner;public class 九_园区参观路径 {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt(); // 长 -> 行数int m sc.nextInt(); // 宽 -> 列数int[][] matrix new int[n][m]; // 地图…

HAproxy反向代理与负载均衡

目录 一、HAproxy介绍 1. 概述 2. 关于4/7层负载均衡 2.1 无负载均衡 2.1.1 图示 2.1.2 说明 2.2 四层负载均衡 2.2.1 图示 2.2.2 说明 2.3 七层负载 2.3.1 图示 2.3.2 说明 3. 特性 4. HAProxy负载均衡常见策略 5. 处理模式 二、HAproxy安装 1. yum安装 2. 第…

算法---双指针练习-7(三数之和)

三数之和 1. 题目解析2. 讲解算法原理3. 编写代码 1. 题目解析 题目地址&#xff1a;三数之和 2. 讲解算法原理 首先对输入的数组进行排序&#xff0c;以便后续使用双指针法。初始化一个空的二维向量 ret&#xff0c;用于存储结果。使用一个循环遍历数组中的每个元素&#xff…

Spark性能优化指南——高级篇

调优概述 有的时候&#xff0c;我们可能会遇到大数据计算中一个最棘手的问题——数据倾斜&#xff0c;此时Spark作业的性能会比期望差很多。数据倾斜调优&#xff0c;就是使用各种技术方案解决不同类型的数据倾斜问题&#xff0c;以保证Spark作业的性能。 数据倾斜发生时的现…

【Idea】八种Debug模式介绍

1.行断点 在对应的代码行左侧边栏点击鼠标左键&#xff0c;会出现一个红色圆圈&#xff0c;以debug模式执行时当代码运行到此处则会停止&#xff0c;并可以查询相关上下文参数 2.方法断点 在方法左侧点击创建断点,在方法进入时会停止&#xff0c;同时可以右键断点&#xff0c;…

Jenkins Pipeline实现Golang项目的CI/CD

Jenkins Pipeline实现Golang项目的CI/CD 背景 最近新增了一个Golang实现的项目&#xff0c;需要接入到现有的流水线架构中。 流程图 这边流程和之前我写过的一篇《基于Jenkins实现的CI/CD方案》差不多&#xff0c;不一样的是构建现在是手动触发的&#xff0c;没有配置webho…

在 Python 中从键盘读取用户输入

文章目录 如何在 Python 中从键盘读取用户输入input 函数使用input读取键盘输入使用input读取特定类型的数据处理错误从用户输入中读取多个值 getpass 模块使用 PyInputPlus 自动执行用户输入评估总结 如何在 Python 中从键盘读取用户输入 原文《How to Read User Input From t…

Elixir and Pylons 中多态继承和自关联关系的创建

我们知道&#xff0c;在Elixir和Pylons中&#xff0c;多态继承和自关联关系是两个独立的概念&#xff0c;分别用于处理不同的情况。而在Pylons中&#xff0c;多态继承通常由SQLAlchemy提供的 polymorphic 关系来实现。下面分别介绍在Elixir和Pylons中如何创建多态继承和自关联关…

vue之性能优化

1.路由懒加载 所谓路由懒加载&#xff0c;其实就是路由通过import动态引入&#xff0c;而不是在文件最上面一个个全部引入&#xff0c;因为JS执行的时候会优先执行引入的文件&#xff0c;如果一次性引入过多&#xff0c;则会增加处理时长。 2.图片懒加载 图片在网页加载过程…

从零搭建React18.2+ReactRoute6.22+TS5+RTK2.2搭配antd5+antd-style书写All in Js完整体验项目规范

1. 使用CRA创建项目 全局设置npm淘宝镜像源 npm config set registry https://registry.npmmirror.com -g使用最新版create-react-app初始化项目结构 npx create-react-app custom-template --template typescript初始化项目之后在package.json文件中配置使用node>18.0.0…