首页 > 其他分享 >高清图解28个高并发之数据结构/数据结构场景匹配技巧分析(高并发精通篇一)

高清图解28个高并发之数据结构/数据结构场景匹配技巧分析(高并发精通篇一)

时间:2024-10-12 18:18:34浏览次数:10  
标签:哈希 删除 元素 28 链表 并发 数组 数据结构 节点

Java 集合以 ArrayList、LinkedList、HashSet、TreeSet 和 HashMap 等组件为核心,构筑了强大而灵活的数据结构体系。这些组件精心设计以满足不同的性能和功能需求,如 ArrayList 的动态数组支持快速随机访问,而 LinkedList 的双向链表结构则擅长于频繁的插入和删除操作。HashSet 基于哈希表提供高效的元素查找,TreeSet 则通过红黑树维持元素排序。对于多线程环境,CopyOnWriteArraySet 和 ConcurrentHashMap 等并发集合保证了线程安全,同时优化了读写性能。这些设计精妙的组件,不仅提升了数据处理的效率,也简化了复杂问题的解决方案,了解他的设计就掌握了他的原理,本篇注重设计。

肖哥弹架构 跟大家“弹弹”  高并发锁,  关注公号回复 'mvcc' 获得手写数据库事务代码

欢迎 点赞,关注,评论。

关注公号Solomon肖哥弹架构获取更多精彩内容SS

历史热点文章

1、JDK集合数据结构范围

1.1. 列表(List)

  • ArrayList: 基于动态数组实现,支持快速随机访问。

  • LinkedList: 基于双向链表实现,适合频繁的插入和删除操作。

  • CopyOnWriteArrayList: 线程安全的变体,写操作时复制数组。

1.2. 集合(Set)

  • HashSet: 基于 HashMap 实现,保证元素唯一性。

  • LinkedHashSet: 哈希表和链表实现,维护元素插入顺序。

  • TreeSet: 基于红黑树,元素处于排序状态。

  • CopyOnWriteArraySet: 线程安全的变体,写操作时复制数组。

1.3. 队列(Queue)

  • LinkedListQueue (作为队列使用时): 支持先进先出(FIFO)。

  • ArrayDeque: 双端队列,支持快速插入和删除。

  • PriorityQueue: 支持优先级排序的队列。

  • ConcurrentLinkedQueue: 线程安全的无界队列。

  • BlockingQueue: 支持阻塞操作的队列接口,具体实现包括:

    • ArrayBlockingQueue: 有界阻塞队列。

    • LinkedBlockingQueue: 基于链表结构的阻塞队列。

    • PriorityBlockingQueue: 具有优先级的阻塞队列。

    • SynchronousQueue: 不存储元素的阻塞队列,主要用于任务窃取。 

1.4. 双端队列(Deque)

  • ArrayDeque: 基于动态数组,实现双向队列。

  • LinkedList (作为双端队列使用时): 基于链表,实现双向队列。

1.5. 映射(Map)

  • HashMap: 基于哈希表,存储键值对。

  • LinkedHashMap: 哈希表加链表,维护插入顺序。

  • TreeMap: 基于红黑树,键处于排序状态。

  • Hashtable: 古老的 Map 实现,线程安全。

  • ConcurrentHashMap: 线程安全的 HashMap 实现。

  • ConcurrentSkipListMap: 线程安全的 TreeMap 实现。

  • IdentityHashMap: 使用 == 比较键的身份,而不是使用 equals() 方法。

  • WeakHashMap: 键是弱引用,适合缓存使用。

1.6. 其他

  • Vector: 古老的动态数组实现,线程安全。

  • Stack: 古老的栈实现,可以使用 Vector 或 Deque 实现。

  • Properties: 用于处理配置文件的集合类。

2、集合数据结构设计与分析

2.1 ArrayList

ArrayList 是 Java 集合框架中的一个非常核心的类,实现了 List 接口。以下是 ArrayList 的设计:

设计思考:
  1. 需求场景

    • 在许多编程任务中,需要一个能够动态增长和收缩的数组。例如,在实现数据集合、缓冲区管理、实现其他数据结构(如栈、队列)等场景中,动态数组是非常有用的。

  2. 现有技术局限性

    • 传统的数组类型在 Java 中是固定长度的,一旦创建,其大小不能改变,这限制了其在需要动态大小管理时的使用。

  3. 技术融合

    • ArrayList 融合了动态数组的概念,提供了一个能够根据需要自动调整大小的数组。

  4. 设计理念

    • ArrayList 提供了一个能够根据添加元素的数量动态增长的数组,同时保持了随机访问的能力,使其在执行索引位置的查找时非常高效。

  5. 实现方式

    • ArrayList 内部使用一个可变大小的数组(默认为空,随着元素添加自动扩容)来存储元素,当数组容量不足以容纳更多元素时,会自动创建一个更大的新数组,并将旧数组中的元素复制到新数组中。

2.1.1 数据结构

图说明:
  • ArrayList:

    • Java 集合框架中的一个类,实现了 List 接口。

  • Object[] elementData:

    • ArrayList 内部使用一个动态数组来存储元素,这个数组的类型是 Object[],可以存储任何类型的对象。

    • 当数组容量不足以存储更多元素时, ArrayList 会自动进行扩容,通常是将数组大小增加到原来的1.5倍。

  • int size:

    • 表示 ArrayList 中实际存储的元素数量。

    • size 与 elementData 数组的 length 属性不同, length 表示数组的总容量,而 size 表示当前存储的元素个数。

2.1.2 执行流程

图说明:
  • 初始化 ArrayList:

    • 创建一个空的 ArrayList 或指定初始容量的 ArrayList

  • 检查容量:

    • 在添加元素前,检查当前数组容量是否足够。

  • 添加元素:

    • 尝试将新元素添加到 ArrayList

  • 容量不足:

    • 如果当前容量不足以容纳新元素,进入扩容流程。

  • 扩容:

    • 创建一个新的数组,容量通常是原数组的1.5倍。

  • 复制旧数组到新数组:

    • 将旧数组中的所有元素复制到新数组中。

  • 增加新元素:

    • 在新数组中插入新元素。

  • 获取元素:

    • 根据索引获取元素。

  • 索引检查:

    • 检查索引是否在有效范围内。

  • 返回元素:

    • 返回指定索引处的元素。

  • 删除元素:

    • 删除 ArrayList 中的指定元素。

  • 移除指定索引元素:

    • 将指定索引处的元素移除。

  • 数组元素向前移动:

    • 将移除元素之后的元素向前移动一位,填补空位。

2.2 LinkedList

LinkedList 在 Java 中是基于双向链表实现的,它包含多个节点,每个节点都包含数据和两个引用,分别指向前一个节点和后一个节点。以下是 LinkedList 的设计:

设计思考:
  1. 需求场景

    • 在许多编程任务中,需要一个可以快速进行插入和删除操作的动态数组。例如,在实现栈、队列、双向队列等数据结构时,这些操作非常常见。

  2. 现有技术局限性

    • ArrayList 提供了快速的随机访问能力,但在进行插入和删除操作时,可能需要移动数组中的大量元素,导致效率低下。

    • Vector 类似于 ArrayList,但它是线程安全的,但使用 synchronized 进行同步,导致并发性能较差。

  3. 技术融合

    • LinkedList 结合了链表的插入和删除效率高的特点,并提供了双向链表的实现,允许从两端快速地添加或移除元素。

  4. 设计理念

    • LinkedList 通过使用链表结构,可以有效地进行插入和删除操作,因为这些操作仅需要改变节点的指针,而不需要移动整个数组。

    • 它还实现了 List 接口,提供了与 ArrayList 相同的接口,但具有不同的性能特性。

  5. 实现方式

    • LinkedList 由一系列 Node 对象组成,每个 Node 包含数据和两个引用( previous 和 next),分别指向前一个和后一个节点。

2.2.1 数据结构

 以下是 LinkedList 数据结构的主要特点:

  1. 链式存储:元素在内存中不是连续存储的,而是通过指针(引用)连接起来的。

  2. 节点结构:每个节点至少包含两部分信息,一个是存储数据的元素,另一个是指向同链表中下一个节点的引用。在双向链表中,还会有一个指向前一个节点的引用。

  3. 动态大小: LinkedList 的大小是动态的,可以根据需要随时插入或删除节点。

  4. 允许空链表:可以创建一个不包含任何节点的空链表。

  5. 插入和删除效率高:在链表的任意位置插入或删除节点的操作时间复杂度为 O(1),因为这些操作只涉及到节点的引用的改动。

  6. 访问元素效率低:访问特定索引位置的元素需要从头节点开始遍历链表,时间复杂度为 O(n)。

  7. 没有空间浪费:与数组不同,链表不需要预先分配固定大小的存储空间。

  8. 有序性:链表中的节点按照它们被插入的顺序保持有序。

  9. 可以实现为双向或循环链表:标准的 LinkedList 实现可以是双向的,也可以是循环的(尾节点指向头节点)。

2.2.1 执行流程

图说明:
  • 初始化 LinkedList:

    • 创建一个空的 LinkedList 实例。

  • 添加元素:

    • 将新元素添加到 LinkedList

  • 删除元素:

    • 从 LinkedList 删除指定的元素。

  • 访问元素:

    • 根据索引访问 LinkedList 中的元素。

  • 遍历 LinkedList:

    • 通过节点间的链接顺序遍历整个 LinkedList

  • 检查边界条件:

    • 在执行索引相关操作前,检查索引是否在有效范围内。

  • 获取节点:

    • 获取指定索引处的节点。

  • 更新节点指针:

    • 在添加或删除元素时,更新节点间的指针。

  • 返回节点数据:

    • 返回指定节点的数据。

  • LinkedList 节点:

    • LinkedList 由一系列节点组成,每个节点包含前一个节点、后一个节点和节点数据。

  • Node prev:

    • 节点中保存的对前一个节点的引用。

  • Node next:

    • 节点中保存的对后一个节点的引用。

  • Node data:

    • 节点中保存的数据。

2.3 CopyOnWriteArrayList

CopyOnWriteArrayList 在 Java 中是一个线程安全的变体数组列表,其特点是在修改(写操作)时通过复制整个底层数组来实现,以此保证读操作的线程安全和高性能。以下是 CopyOnWriteArrayList 的设计:

设计思考:
  1. 需求场景

    • 在多线程环境中,读操作远比写操作频繁,且对数据的实时性要求不是非常高的场景。例如,缓存系统、实时数据的订阅发布模型等。

  2. 现有技术局限性

    • 传统的线程安全实现,如 Vector 或通过 synchronized 同步代码块或方法,可能会因为写操作导致的线程阻塞,严重影响并发性能。

  3. 技术融合

    • CopyOnWriteArrayList 采用了写时复制(Copy-On-Write)的策略,当进行写操作(添加、删除等)时,先复制整个数组,然后在新数组上进行操作,而读操作则直接作用于原数组,从而提高了读操作的性能。

  4. 设计理念

    • 利用了读操作远多于写操作的特性,通过分离读和写操作,使得读操作无需加锁,从而提高了并发读的性能。

  5. 实现方式

    • 内部使用一个数组来存储元素,所有写操作都会创建一个新的数组,并将修改应用于新数组,然后原子性地将内部数组引用指向新数组。

2.3.1 数据结构

图说明:
  • CopyOnWriteArrayList:

    • 表示 CopyOnWriteArrayList 的实例。

  • Object[] array:

    • CopyOnWriteArrayList 内部使用的一个数组 array 来存储元素。这是原始数组,所有读操作都访问这个数组。

  • Object[] newArray:

    • 写操作时创建的新数组。当写操作发生时,这个数组是原始数组的一个深拷贝。

  • 写操作:

    • 包括添加、删除或修改元素。写操作不是在原始数组上进行,而是在新数组上进行。

工作原理:
  1. 读操作:

    • 多个读线程可以同时访问和遍历 array,因为数组是不可变的。

  2. 写操作:

    • 当写操作发生时(如添加、删除或修改元素),写线程首先会创建原始 array 的一个副本 newArray

    • 写线程在 newArray 上进行添加、删除或修改操作。

    • 写操作完成后,写线程会原子性地将 CopyOnWriteArrayList 的内部数组引用指向 newArray

  3. 数据一致性:

    • 在写操作进行时,读线程仍然可以访问旧的内部数组 array,从而保证了数据的一致性。

2.3.2 执行流程

图说明:
  • 初始化 CopyOnWriteArrayList:

    • 创建一个空的 CopyOnWriteArrayList 实例。

  • 内部数组 array:

    • CopyOnWriteArrayList 内部使用一个数组来存储元素。

  • 读操作:

    • 直接读取内部数组的元素,是线程安全的,因为内部数组不可变。

  • 写操作:

    • 包括添加、删除和修改元素,需要创建内部数组的一个新副本。

  • 复制数组:

    • 在执行写操作前,复制内部数组,以保证新元素的添加不会影响读操作。

  • 添加元素:

    • 向 CopyOnWriteArrayList 添加新元素。

  • 删除元素:

    • 从 CopyOnWriteArrayList 删除元素。

  • 修改元素:

    • 修改 CopyOnWriteArrayList 中的元素。

  • 数组拷贝:

    • 创建内部数组的一个新副本,并在新副本上执行写操作。

2.4 HashSet

HashSet 是 Java 集合框架中的一个基本成员,它是 java.util 包下的一个非常常用的集合类。以下是 HashSet 的设计:

设计思考:
  1. 需求场景

    • 在很多应用场景中,需要存储不重复的元素,并且需要快速地添加、删除和查找元素。

    • 例如,在处理配置选项、用户权限、邮件地址列表等场景时,确保元素的唯一性是非常重要的。

  2. 现有技术局限性

    • ArrayList 和 LinkedList 虽然可以存储元素,但它们需要线性时间来查找元素,且不保证元素的唯一性。

  3. 技术融合

    • HashSet 基于 HashMap 实现,它结合了哈希表的快速查找特性来提供常数时间复杂度的添加、删除和查找操作,同时保证了元素的唯一性。

  4. 设计理念

    • HashSet 提供了一个不允许重复元素的数据结构,它使用哈希表的键来存储元素,而不关心值。

    • 这种设计使得 HashSet 在保证元素唯一性的同时,提供了高效的操作性能。

  5. 实现方式

    • HashSet 的每个元素都作为 HashMap 的一个键存储,而对应的值是一个固定的对象(通常是一个名为 PRESENT 的私有静态对象)。

2.4.1 数据结构

图说明:
  • HashSet:

    • 表示 HashSet 类的实例,用于存储不重复的元素。

  • HashMap:

    • HashSet 的内部实现基于 HashMap

  • 数组 (Buckets) :

    • HashMap 使用一个数组来存储桶(Buckets),桶是用于存储 Entry 对象的容器。

  • 索引1, 索引2, 索引3:

    • 表示数组中的具体索引位置,每个索引对应一个桶。

  • Entry (链表/红黑树) :

    • 每个桶可以包含多个 Entry 对象,它们通过链表或红黑树形式连接。

  • 链表 Entry:

    • 在哈希冲突较少的情况下, Entry 对象通过链表连接。

  • 红黑树 Entry:

    • 当链表长度超过阈值时,链表可能会被转换成红黑树以提高搜索效率。

2.4.2 执行流程

图说明:
  • 创建 HashSet 实例:

    • 初始化 HashSet 对象。

  • 添加元素:

    • 将元素添加到 HashSet

  • 计算元素的hashCode:

    • 调用元素的 hashCode() 方法计算其哈希码。

  • 确定数组索引位置:

    • 根据哈希码和数组长度确定数组索引位置。

  • 处理哈希冲突:

    • 如果索引位置已有元素,处理哈希冲突。

  • 元素添加至链表/红黑树:

    • 将新元素添加至对应索引的链表或红黑树中。

  • 删除元素:

    • 从 HashSet 删除元素。

  • 计算元素的hashCode:

    • 调用元素的 hashCode() 方法计算其哈希码。

  • 确定数组索引位置:

    • 根据哈希码和数组长度确定数组索引位置。

  • 找到对应的哈希桶:

    • 定位到数组中对应的哈希桶。

  • 从链表/红黑树中删除元素:

    • 从对应索引的链表或红黑树中删除元素。

  • 遍历 HashSet:

    • 遍历 HashSet 中的所有元素。

  • 获取数组:

    • 获取 HashSet 内部的数组。

  • 遍历每个桶:

    • 遍历数组的每个桶。

  • 遍历链表/红黑树:

    • 遍历桶内的链表或红黑树中的所有元素。

2.5 LinkedHashSet

LinkedHashSet 是 Java 集合框架中的一个成员,它结合了 HashSet 的快速查找特性和 LinkedList 的插入顺序保持功能。以下是 LinkedHashSet 的设计:

设计思考:
  1. 需求场景

    • 在很多应用场景中,需要快速地插入、删除和查找元素,同时也需要保持元素的插入顺序。

    • 例如,在处理用户会话、缓存实现、任务调度等场景时,保持元素的添加顺序是非常重要的。

  2. 现有技术局限性

    • HashSet 提供了常数时间的添加、删除和查找性能,但它不保持元素的插入顺序。

    • TreeSet 保持了元素的排序顺序,但不是插入顺序,且它的性能不如 HashSet

    • ArrayList 和 LinkedList 保持了插入顺序,但它们的查找性能为线性时间复杂度。

  3. 技术融合

    • 为了结合 HashSet 的快速查找能力和 LinkedList 的插入顺序保持能力, LinkedHashSet 应运而生。

  4. 设计理念

    • LinkedHashSet 底层使用 HashMap 来存储元素,保证了快速的查找性能。

    • 同时,它在每个 HashMap 的条目上使用一个双向链表来维护元素的插入顺序。

  5. 实现方式

    • LinkedHashSet 继承自 HashSet,但重写了 add、 iterator 等方法,以维护插入顺序。

    • 它在内部维护了与 HashMap 条目关联的双向链表的节点,这些节点链接了具有相同哈希值但插入顺序不同的元素。

2.5.1 数据结构

图说明:
  • LinkedHashSet:

    • 表示 LinkedHashSet 类的实例,它继承自 HashSet 并维护元素的插入顺序。

  • HashMap:

    • LinkedHashSet 的实现基于 HashMap,用来存储集合中的元素。

  • 数组 (Buckets) :

    • HashMap 使用一个数组来存储桶(Buckets),桶是用于存储 Entry 对象的容器。

  • 哈希桶:

    • 每个桶内部使用链表来解决哈希冲突。

  • 链表 Entry:

    • 每个桶包含多个 Entry 对象,它们通过链表连接。

  • 红黑树 Entry:

    • 当链表长度超过阈值时,链表可能会被转换成红黑树以提高搜索效率。

  • 链表 节点1 和 链表 节点2:

    • 表示链表中的节点,每个节点存储着集合中的一个元素,并指向前一个和后一个节点,形成双向链表。

  • 元素:

    • 存储在 LinkedHashSet 中的最终数据。

2.5.2 执行流程

图说明:
  • 创建 LinkedHashSet 实例:

    • 初始化 LinkedHashSet 对象。

  • 添加元素:

    • 将元素添加到 LinkedHashSet

  • 计算元素的hashCode:

    • 调用元素的 hashCode() 方法计算其哈希码。

  • 确定数组索引位置:

    • 根据哈希码和数组长度确定数组索引位置。

  • 找到对应的哈希桶:

    • 定位到数组中对应的哈希桶。

  • 检查哈希桶中的链表/红黑树:

    • 检查哈希桶中是否已有链表或红黑树结构。

  • 处理哈希冲突:

    • 如果桶中已有元素,处理哈希冲突。

  • 元素添加至链表/红黑树:

    • 将新元素添加至对应索引的链表或红黑树中。

  • 删除元素:

    • 从 LinkedHashSet 删除元素。

  • 重新计算元素的hashCode:

    • 调用元素的 hashCode() 方法计算其哈希码。

  • 确定删除元素的数组索引位置:

    • 根据哈希码和数组长度确定数组索引位置。

  • 找到删除元素的哈希桶:

    • 定位到数组中对应的哈希桶。

  • 从链表/红黑树中删除元素:

    • 从对应索引的链表或红黑树中删除元素。

  • 遍历 LinkedHashSet:

    • 遍历 LinkedHashSet 中的所有元素。

  • 获取数组:

    • 获取 LinkedHashSet 内部的数组。

  • 遍历每个桶:

    • 遍历数组的每个桶。

  • 遍历链表/红黑树:

    • 遍历桶内的链表或红黑树中的所有元素。

  • 读取元素:

    • 读取链表或红黑树中的元素。

2.6 TreeSet

TreeSet 是 Java 集合框架中的一个有序集合类,实现了 Set 接口。以下是 TreeSet 的设计:

设计思考:
  1. 需求场景

    • 在许多编程任务中,需要存储不重复的元素,并且这些元素需要保持一定的顺序,例如,自然排序或自定义排序顺序。

    • 例如,在处理需要排序的配置选项、用户权限、需要按顺序处理的任务列表等场景时,元素的排序顺序是非常重要的。

  2. 现有技术局限性

    • HashSet 提供了非常快的查找、添加和删除操作,但它不保证元素的任何特定顺序。

    • ArrayList 和 LinkedList 可以保持插入顺序,但查找操作需要线性时间。

  3. 技术融合

    • TreeSet 结合了 HashSet 的快速查找特性和 ArrayListLinkedList 的元素顺序保持功能,但通过使用红黑树(一种自平衡的二叉搜索树)实现,提供了有序的元素集合。

  4. 设计理念

    • TreeSet 提供了一个不允许重复元素的数据结构,同时保证了元素处于排序状态,可以进行有效的范围查询和排序操作。

  5. 实现方式

    • TreeSet 内部使用 TreeMap 的实例来存储元素,其中元素作为键,值是一个固定的虚拟对象(如 PRESENT),从而保证了元素的唯一性。

2.6.1 数据结构

图说明:
  • TreeSet:

    • 表示 TreeSet 类的实例,它实现了 Set 接口,并保证元素处于排序状态。

  • TreeMap:

    • TreeSet 基于 TreeMap 实现,其中元素作为键存储,而不关心值。

  • 红黑树:

    • TreeMap 的底层数据结构是一个红黑树,它是一个自平衡的二叉搜索树。

  • 根节点:

    • 红黑树的根节点,是树的入口。

  • 左子节点和右子节点:

    • 表示红黑树节点的子节点。

  • 元素A, 元素B, 元素C:

    • 实际存储在 TreeSet 中的数据。

2.6.2 执行流程

图说明:
  1. 添加元素

    • 计算元素的自然排序:根据元素的自然顺序或提供的 Comparator 计算排序。

    • 构建红黑树:TreeSet 基于红黑树数据结构,确保元素处于排序状态。

    • 确定插入位置:在红黑树中找到元素的插入位置。

    • 插入元素到红黑树:将元素插入到红黑树中。

  2. 删除元素

    • 计算元素的自然排序:根据元素的自然顺序或提供的 Comparator 计算排序。

    • 查找红黑树:在红黑树中查找要删除的元素。

    • 删除元素从红黑树:从红黑树中删除元素。

  3. 遍历 TreeSet

    • 获取红黑树根节点:获取红黑树的根节点,开始遍历。

    • 遍历红黑树节点:遍历红黑树的每个节点。

    • 读取元素:从红黑树的节点中读取元素。

2.7 CopyOnWriteArraySet

CopyOnWriteArraySet 是 Java 并发包 java.util.concurrent 中的一个集合类,它是 CopyOnWriteArrayList 的一个变体,用于维护一个线程安全的、动态的元素集合。以下是 CopyOnWriteArraySet 的设计:

设计思考:
  1. 需求场景

    • 在多线程环境中,读操作频繁而写操作相对较少的场景,如缓存、实时数据集、事件监听器集合等。

  2. 现有技术局限性

    • 传统的线程安全集合,如 Collections.synchronizedSet 或 Hashtable,在读多写少的场景下可能因为写操作导致的线程阻塞,影响性能。

  3. 技术融合

    • CopyOnWriteArraySet 采用了写时复制(Copy-On-Write)的策略,在读操作远多于写操作的情况下,提高了读操作的性能。

  4. 设计理念

    • CopyOnWriteArraySet 利用了读操作远多于写操作的特点,在读操作时不需要加锁,从而提高了并发读的性能。

  5. 实现方式

    • 内部使用 CopyOnWriteArrayList 存储元素,所有写操作(添加、删除等)都会创建一个新的数组副本,然后对新数组进行修改,最后原子性地将内部数组引用指向新数组。

2.7.1 数据结构

图说明
  • CopyOnWriteArraySet:表示 CopyOnWriteArraySet 类的实例,它提供了线程安全的 Set 集合功能。

  • CopyOnWriteArrayList:CopyOnWriteArraySet 基于 CopyOnWriteArrayList 实现,后者是线程安全的 ArrayList 实现。

  • 内部数组:CopyOnWriteArrayList 初始的内部数组,用于存储集合中的元素。

  • 内部数组副本:当执行写操作(如添加、删除)时,CopyOnWriteArrayList 创建内部数组的一个副本。

  • 新内部数组:写操作完成后,CopyOnWriteArrayList 将内部数组引用指向新的数组副本。

  • 元素1、元素2、元素n:表示存储在 CopyOnWriteArraySet 中的实际数据。

2.7.1 执行流程

图说明
  • 创建 CopyOnWriteArraySet 实例:初始化 CopyOnWriteArraySet 对象。

  • 添加元素:将元素添加到 CopyOnWriteArraySet。

  • 复制旧内部数组:为了添加元素,先复制当前的内部数组。

  • 修改新内部数组副本:在数组的副本上添加元素。

  • 将新内部数组副本设置为当前:将修改后的数组副本设置为当前数组,完成添加操作。

  • 删除元素:从 CopyOnWriteArraySet 删除元素。

  • 复制旧内部数组:为了删除元素,先复制当前的内部数组。

  • 修改新内部数组副本:在数组的副本上删除元素。

  • 将新内部数组副本设置为当前:将修改后的数组副本设置为当前数组,完成删除操作。

  • 遍历 CopyOnWriteArraySet:遍历 CopyOnWriteArraySet 中的所有元素。

  • 读取当前内部数组:读取当前的内部数组,进行遍历操作。

其他内容在第二篇文章《高清图解28个高并发之数据结构/数据结构场景匹配技巧分析(高并发精通篇二)》中。。。

原创不易,喜欢作者打赏,您的支持是我坚持原创和分享的最大动力!文章有帮助的话,点击 在看转发吧。

谢谢支持哟 (^__^)

标签:哈希,删除,元素,28,链表,并发,数组,数据结构,节点
From: https://blog.csdn.net/alises1314/article/details/142829227

相关文章

  • Project Euler 728 题解
    Problem728CircleofCoins得到Wallbreaker5th的指导。\(F\)就是求这些环上区间(记为\(A\))的异或线性基大小。令\(A'_i\getsA_i\oplusA_{i+1}\)。现在求\(\langA'\rang\)的线性基。如果可能从全黑和全白间转换,那么\(\dim\langA'\rang=\langA\rang-1\),否则不\(-1......
  • 如何查看GB28181流媒体平台LiveGBS中对GB28181实时视频数据统计的负载信息
    @目录1、负载信息2、负载信息说明3、会话列表查看3.1、会话列表4、停止会话5、搭建GB28181视频直播平台1、负载信息实时展示直播、回放、播放、录像、H265、级联等使用数目2、负载信息说明直播:当前推流到平台的实时视频数目回放:当前推流到平台的回放视频数目播放:当前观看......
  • 海康大华宇视等摄像头/执法记录仪等设备通过GB28181注册到LiveGBS流媒体平台,如何实时
    @目录1、如何监听设备状态2、device订阅2.1、设备上线消息2.2、设备离线消息2.2、通道上线消息2.2、通道离线消息3、订阅示例3.1、连接REDIS3.2、订阅device示例3.3、设备上线示例3.3.1、注册上线后3.4、设备离线示例3.4.1、注销离线后4、更多4.1、如何切换redis5、搭建GB28181视......
  • 链表-数据结构
    链表的连接简单题目描述:创建两个链表:S1,S2;让s1和s2实现合并连接;连接要求:输入s1节点的数值下标和输入s2的数值下标,如果数值相同实现连接;比如:cin>>s1(2),cin>>s2(0);就让s1的下标2:数值1和s2的下标0:数值1比较相同--------321123s1数值1在跟s......
  • 2024.10.7(数据结构的栈)
    顺序栈是利用顺序存储结构实现的栈,指针top指示栈顶在顺序栈的位置。base为存储空间基地址,S.top-S.base是栈中元素的个数,类似Length。栈为空时:S.topS.base;栈满时:S.top-S.baseMAXSIZE;顺序栈,top在最高元素的上一个,base位置是最低元素,故取栈顶元素要取top-1的:队列先进先出。......
  • 数据结构与算法 - 单链表 & 双链表 -- 概念+实现
    文章目录前言一、顺序表的缺陷二、链表是如何设计的?三、链表的分类四、链表的概念及其结构1、链表的概念:2、链表的结构五、不带头单向不循环链表的实现(一)、SList.h的实现(二)、SList.c的实现1、初始化2、创建结点3、头插4、尾插4、头删5、尾删6、指定p......
  • CSP-S 模拟赛 28
    CSP-S模拟赛28T1签到题。对\(b\)分解质因数后便容易求解。T2考虑枚举\(\gcd(S)\)的取值\(x\),则\(\operatorname{lcm}(S)=m-x\)。那么同时变形\(\gcd\)和\(\operatorname{lcm}\)变为\(\gcd(S)=1,\operatorname{lcm}(S)=\dfrac{m-x}{x}\)。那么对于\(\gcd\)......
  • 【趣学C语言和数据结构100例】
    【趣学C语言和数据结构100例】问题描述一个球从100m高度自由落下,每次落地后反弹回原高度的一半,再落下,求它在第10次时共经过多少米,第10次反弹多高。猴子吃桃问题。猴子第1天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第2天早上又将剩下的桃子吃掉一......
  • Redis原理篇 之数据结构
    Redis原理篇之数据结构文章目录Redis原理篇之数据结构1动态字符串SDS1.1SDS介绍1.2SDS扩容1.3SDS优点2IntSet2.1IntSet介绍2.2IntSet升级2.3总结3Dict3.1Dict的原理3.2Dict的扩容3.3Dict的收缩3.4Dict的rehash3.5总结4ZipList4.1ZipList原理4.2Zi......
  • HALCON数据结构之数组
    1.1Tuple数组的基本操作*1、Tuple数组元素的创建*1.1、创建一个空数组assign([],empty_tuple)//采用赋值操作empty_tuple:=[]//采用赋值操作*1.2、创建一个整型数组assign([1,2,3,4,5,6,7,8,9,10],tupleInt1)//采用赋值操作tupleInt1:=[1,0,3,4,5,6,7,8,9]/......