首页 > 编程语言 >Java 并发集合容器

Java 并发集合容器

时间:2024-12-02 09:02:58浏览次数:8  
标签:容器 Java 队列 元素 阻塞 并发 线程

在多线程编程中,高效地访问和操作数据结构是一个重要的挑战。Java 提供了并发集合容器(Concurrent Collection Containers)来解决这个问题。这些容器通过内部的同步机制实现了线程安全,使得开发者无需显式同步代码就能在并发环境下安全使用。本文将详细介绍 Java 并发集合容器中的几个重要类,包括 ConcurrentHashMap、阻塞队列和 CopyOnWrite 容器。

1 并发 Map

1.1 ConcurrentMap 接口

ConcurrentMap 接口继承自 Map 接口,并在其基础上增加了四个方法:

public interface ConcurrentMap<K, V> extends Map<K, V> {

    //插入元素
    V putIfAbsent(K key, V value);

    //移除元素
    boolean remove(Object key, Object value);

    //替换元素
    boolean replace(K key, V oldValue, V newValue);

    //替换元素
    V replace(K key, V value);

}
  • putIfAbsent(K key, V value): 如果指定的键不存在,则插入键值对。如果键已存在,则不替换原有的值。
  • remove(Object key, Object value): 删除指定的键值对。只有当键和值都匹配时,才会删除。
  • replace(K key, V oldValue, V newValue): 替换指定的键值对。只有当键和旧值都匹配时,才会替换。
  • replace(K key, V value): 替换指定的键值对。如果键存在,则直接替换。

1.2 ConcurrentHashMap

ConcurrentHashMapConcurrentMap 接口的主要实现类,它提供了高效的并发性和伸缩性。与 Hashtable 不同,ConcurrentHashMap 采用了更细粒度的锁策略,避免了全局锁,从而提高了并发性能。

ConcurrentHashMap 适用于读密集型操作,因为它允许在读操作时无需加锁。对于写操作,ConcurrentHashMap 使用了分段锁(Segment)来减少锁的竞争。

1.3 ConcurrentSkipListMap

ConcurrentSkipListMapConcurrentNavigableMap 接口的实现类,底层使用跳表(SkipList)数据结构。跳表是一种“空间换时间”的数据结构,能够提供有序的键值对存储。

ConcurrentHashMap 相比,ConcurrentSkipListMap 的读写性能相对较低,但提供了元素的有序性。适用于需要线程安全且元素有序的场景。

2 并发 Queue

JDK 并没有提供线程安全的 List 类,因为对于 List 来说,很难开发一个通用且没有并发瓶颈的线程安全的 List。因此,JDK 提供了线程安全的队列和双端队列:ConcurrentLinkedQueueConcurrentLinkedDeque

这两个类使用 CAS(Compare-And-Swap)操作来实现线程安全,适用于高并发的场景。

3 并发 Set

ConcurrentSkipListSet 是线程安全的有序集合,底层使用 ConcurrentSkipListMap 实现。它适用于需要线程安全且元素有序的场景。

此外,谷歌的 Guava 库提供了一个线程安全的 ConcurrentHashSet

Set<String> s = Sets.newConcurrentHashSet();

4 阻塞队列

阻塞队列(BlockingQueue)是 Java util.concurrent 包下的重要数据结构,适用于生产者-消费者模式。阻塞队列提供了线程安全的队列访问方式,简化了并发编程的复杂性。

4.1 BlockingQueue 的操作方法

阻塞队列提供了四组不同的方法用于插入、移除、检查元素:

方法\处理方式抛出异常返回特殊值一直阻塞超时退出
插入方法add(e)offer(e)put(e)offer(e,time,unit)
移除方法remove()poll()take()poll(time,unit)
检查方法element()peek()--
  • 抛出异常: 如果操作无法立即执行,会抛出异常。
  • 返回特殊值: 如果操作无法立即执行,会返回一个特殊值(通常是 truefalse)。
  • 一直阻塞: 如果操作无法立即执行,则一直阻塞或者响应中断。
  • 超时退出: 如果操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。

4.2 BlockingQueue 的实现类

BlockingQueue 是 Java util.concurrent 包下的一个重要接口,提供了线程安全的队列访问方式,适用于生产者-消费者模式。BlockingQueue 有多个实现类,每个实现类都有其特定的用途和特性。下面将详细介绍 BlockingQueue 的几个主要实现类:ArrayBlockingQueueLinkedBlockingQueueDelayQueuePriorityBlockingQueueSynchronousQueue

4.2.1 ArrayBlockingQueue

ArrayBlockingQueue 是一个由数组结构组成的有界阻塞队列。其内部结构是数组,具有数组的特性,如固定大小和随机访问。

public ArrayBlockingQueue(int capacity, boolean fair) {
    // 省略代码
}
  • 初始化队列大小: 一旦初始化,队列大小将不能改变。
  • 公平锁: 构造方法中的 fair 参数表示控制对象的内部锁是否采用公平锁。默认是非公平锁。

4.2.2 LinkedBlockingQueue

LinkedBlockingQueue 是一个由链表结构组成的有界阻塞队列。其内部结构是链表,具有链表的特性,如动态大小和顺序访问。

  • 默认队列大小: 默认队列的大小是 Integer.MAX_VALUE,也可以指定大小。
  • 先进先出原则: 此队列按照先进先出的原则对元素进行排序。

4.2.3 DelayQueue

DelayQueue 是一个没有大小限制的阻塞队列,其中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。注入其中的元素必须实现 java.util.concurrent.Delayed 接口。

  • 插入操作: 往队列中插入数据的操作(生产者)永远不会被阻塞。
  • 获取操作: 只有获取数据的操作(消费者)才会被阻塞。

4.2.4 PriorityBlockingQueue

PriorityBlockingQueue 是一个基于优先级的无界阻塞队列。优先级的判断通过构造函数传入的 Comparator 对象来决定。内部控制线程同步的锁采用的是非公平锁。

public PriorityBlockingQueue(int initialCapacity,
                             Comparator<? super E> comparator) {
    this.lock = new ReentrantLock(); // 默认构造方法-非公平锁
    // 其余代码略
}
  • 无界队列: 不会阻塞数据生产者(因为队列是无界的)。
  • 阻塞消费者: 只会在没有可消费的数据时阻塞数据的消费者。

注意: 使用时要注意生产者生产数据的速度不能快于消费者消费数据的速度,否则会耗尽可用堆内存空间。

4.2.5 SynchronousQueue

SynchronousQueue 是一个比较特殊的队列,没有任何内部容量,甚至连一个队列的容量都没有。每个 put 操作必须等待一个 take 操作,反之亦然。

  • 无容量: 没有任何内部容量。
  • 配对操作: 每个 put 必须等待一个 take,反之亦然。

以下方法的返回值可以帮助理解这个队列:

  • iterator(): 永远返回空,因为里面没有东西。
  • peek(): 永远返回 null
  • put(): 往队列放进去一个元素以后就一直 wait 直到有其他线程进来把这个元素取走。
  • offer(): 往队列里放一个元素后立即返回,如果碰巧这个元素被另一个线程取走了,offer 方法返回 true,否则返回 false
  • take(): 取出并且 remove 掉队列里的元素,取不到东西他会一直等。
  • poll(): 取出并且 remove 掉队列里的元素,只有到碰巧另外一个线程正在往队列里 offer 数据或者 put 数据的时候,该方法才会取到东西。否则立即返回 null
  • isEmpty(): 永远返回 true
  • remove() & removeAll(): 永远返回 false

4.2.6 小结

BlockingQueue 的实现类各有其特点和适用场景:

  • ArrayBlockingQueue: 适用于固定大小的队列,内部使用数组结构。
  • LinkedBlockingQueue: 适用于动态大小的队列,内部使用链表结构。
  • DelayQueue: 适用于需要延迟处理的场景,元素必须实现 Delayed 接口。
  • PriorityBlockingQueue: 适用于需要优先级排序的场景,内部使用非公平锁。
  • SynchronousQueue: 适用于需要严格配对操作的场景,没有任何内部容量。

5 CopyOnWrite 容器

CopyOnWrite 容器是一种写时复制的容器。当有多个调用者同时请求一个资源数据时,如果某个调用者需要对数据进行修改,系统会复制一个当前数据源的副本供其修改,然后将原容器的引用指向新容器。

CopyOnWrite 容器适用于“读多写少”的并发场景,因为它允许在读操作时无需加锁,从而提高了读操作的性能。

JDK 提供了两个 CopyOnWrite 容器:CopyOnWriteArrayListCopyOnWriteArraySet

6 总结

本文详细介绍了 Java 并发集合容器中的几个重要类,包括 ConcurrentHashMap、阻塞队列和 CopyOnWrite 容器。这些容器通过内部的同步机制实现了线程安全,简化了并发编程的复杂性。在实际开发中,根据具体的应用场景选择合适的并发容器,可以显著提高程序的性能和可维护性。

7 思维导图

在这里插入图片描述

8 参考链接

聊聊Java的并发集合容器ConcurrentHashMap、阻塞队列和 CopyOnWrite 容器

标签:容器,Java,队列,元素,阻塞,并发,线程
From: https://blog.csdn.net/gaosw0521/article/details/144021181

相关文章

  • 分类算法学业警示管理系统|Java|SSM|JSP| 前后端分离
    【重要1⃣️】前后端源码+万字文档+部署文档            【包含内容】【一】项目提供非常完整的源码注释【二】相关技术栈文档【三】源码讲解视频                     【其它服务】【一】可以提供远程......
  • Java基础39道常见面试题及详细答案
    最近看到网上流传着,各种面试经验及面试题,往往都是一大堆技术题目贴上去,而没有答案。为此我业余时间整理了,Java基础常见的40道常见面试题,及详细答案,望各路大牛,发现不对的地方,不吝赐教,留言即可。八种基本数据类型的大小,以及他们的封装类引用数据类型Switch能否用string做参数e......
  • Java基础全解:构建扎实编程技能
    文章目录1.HelloWorld程序深入解析:2.数据类型深入解析:3.条件判断深入解析:4.循环结构深入解析:5.数组深入解析:6.方法定义与调用深入解析:1.HelloWorld程序深入解析:类声明:publicclassHelloWorld定义了一个公共类。public关键字意味着这个类可以......
  • HarmonyOS:异步并发 (Promise和async/await)
    一、并发概述并发是指在同一时间内,存在多个任务同时执行的情况。对于多核设备,这些任务可能同时在不同CPU上并行执行。对于单核设备,多个并发任务不会在同一时刻并行执行,但是CPU会在某个任务休眠或进行I/O操作等状态下切换任务,调度执行其他任务,提升CPU的资源利用率。为了......
  • 【娱乐项目】基于批处理脚本与JavaScript渲染视频列表的Web页面
    Demo介绍一个简单的视频播放器应用,其中包含了视频列表和一个视频播放区域。用户可以通过点击视频列表中的项来选择并播放相应的视频,播放器会自动播放每个视频并在播放完毕后切换到下一个视频。本项目旨在通过自动化脚本和动态网页渲染,帮助用户快速生成并展示本地视频资源(......
  • javaweb
    1,静态web是什么(网页)2,动态web是什么Server和Servlet的区别主要在于它们的功能和角色。Server通常指的是一个提供服务的程序或者系统,能够响应客户端的请求并返回响应。而Servlet是一个在Server端运行的程序,专门用于处理用户请求并生成动态的Web内容。Server:Server是提供某种服......
  • JAVA开源毕业设计 医护人员排班系统 Vue.JS+SpringBoot+MySQL
    本文项目编号T014,文末自助获取源码\color{red}{T014,文末自助获取源码}......
  • JAVA开源毕业设计 美容院管理系统 Vue.JS+SpringBoot+MySQL
    本文项目编号T012,文末自助获取源码\color{red}{T012,文末自助获取源码}......
  • 高级java每日一道面试题-2024年12月01日-JVM篇-你知道哪些JVM性能调优参数?
    如果有遗漏,评论区告诉我进行补充面试官:你知道哪些JVM性能调优参数?我回答:在Java高级面试中,JVM性能调优是一个非常重要的主题。了解JVM的性能调优参数可以帮助你更好地管理和优化应用程序的性能。以下是一些常见的JVM性能调优参数及其详细解释:1.堆内存相关参数-Xms......
  • 高级java每日一道面试题-2024年11月30日-JVM篇-Minor GC(年轻代GC)在什么时候发生?
    如果有遗漏,评论区告诉我进行补充面试官:MinorGC(年轻代GC)在什么时候发生?我回答:在Java高级面试中,关于MinorGC(也称为YoungGC或ScavengeGC)何时发生的问题,是一个重要的考点。以下是对MinorGC触发条件的详细解释:一、MinorGC的基本概念MinorGC是Java虚拟机(JVM)中一......